I actually agree that they
technically aren't zero cost (notice I didn't even write that), but the cost is indirect. I've worked on a number of Java JITs and in practice, not a lot of hot code has catch blocks, and even when so, inlining is typically so deep that lots of exception edges (e.g. arising because a possible NPE) get optimized away.
Most of the lost optimization opportunities are second-order costs, not first-order costs. Java JITs make up for the extra flow edges by focusing more on global optimizations rather than local (e.g. GVN vs LVN, global code motion, global flow-sensitive load/store elimination), etc. Generally a possible exception edge splitting a basic block doesn't hurt because the non-exceptional control flow will still benefit from flow-sensitive optimizations (i.e. it has only one predecessor anyway).
We're splitting hairs anyway. Like I said, Java JITs are significantly more advanced at optimizing exception-heavy code. I'd be really surprised if you saw anything more than a 1% increase in performance, actually, no, scratch that. I doubt you can even reliably any speedup distinguishable from noise from just disabling all support for exceptions in most Java code, unless you are talking about metadata. Top-tier JITs really are that good.