熟悉Scala的人知道返回值是代码块的最后一句,通常不能提早返回。return关键字是用抛异常来实现的,这样就能提早脱离代码块了。服务器
最近看Scala源代码,注意到它对return的高效实现,有趣。框架
抛的异常类是NonLocalReturnControl,继承自Throwable,有个字段用来放置要返回的值。编译器把return value大体翻译成throw new NonLocalReturnControl(key/*metadata*/, value)
就能够了。ide
一般Java的异常有三类: Exception, RuntimeException, Error。若是一个对象是Exception但不是RuntimeException,那就是checked exception。而Error一般是JVM抛出的,例如StackOverflowError, OutOfMemoryError, VerifyError,偶尔也有XML库抛Error。总之没有其余直接继承Throwable的类了。翻译
因此在Scala里只要注意别无脑catch Throwable,就不会误拦return了。若是是个服务器程序,不想let it crash,只要catch Exception和Error就行了。code
用抛异常来打断控制流的作法,在有的Web框架中也出现了,没啥。但在一门语言的实现中,必须保证高效。对象
throw和catch都是很快很快的,毕竟只是几个地址操做,慢的是new Exception这一步,这里要让JVM取得当前的一大串stacktrace填充进去,开销约为new 200个Object的程度。继承
Scala的NonLocalReturnControl的窍门是——Override了fillInStackTrace()
方法。这个方法原本会调用native的fillInStackTrace(int)
让JVM去填stacktrace。覆盖成空实现,测一下,开销约为new 6个Object。效果拔群!编译器
还能够提升!去掉synchronized关键字,开销又减半了。最后是new 3个Object的开销,能够接受!it
我想到另外一种实现方案是把value塞到一个ThreadLocal里,异常就没必要包含value了,这样就只需全局new一次异常对象,每次都throw它。开销约为new 1个Object。Clojure就喜欢用ThreadLocal来实现一些特性。不过ThreadLocal悠着点用啊,玩很差是要出大事的(下一篇谈这个问题)。io