[译] Android 的 Java 8 支持

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文原文出自 ","attrs":{}},{"type":"link","attrs":{"href":"https://jakewharton.com/","title":"","type":null},"content":[{"type":"text","text":"jakewharton","attrs":{}}]},{"type":"text","text":" 关于 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"R8","attrs":{}}],"attrs":{}},{"type":"text","text":" 系列文章第一篇。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文链接 : ","attrs":{}},{"type":"link","attrs":{"href":"https://jakewharton.com/androids-java-8-support/","title":"","type":null},"content":[{"type":"text","text":"Android's Java 8 Support","attrs":{}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文作者 : ","attrs":{}},{"type":"link","attrs":{"href":"https://jakewharton.com/","title":"","type":null},"content":[{"type":"text","text":"jakewharton","attrs":{}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"译者 : ","attrs":{}},{"type":"link","attrs":{"href":"https://juejin.cn/user/2172290705131016","title":"","type":null},"content":[{"type":"text","text":"Antway","attrs":{}}]}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我在家办公已经有几年了,在此期间,我听到周围的人抱怨 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 对 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 不同版本的支持力度。在每年的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Google I/O","attrs":{}}],"attrs":{}},{"type":"text","text":" 大会上,你都会发现我针对这个问题在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"fireside chats","attrs":{}}],"attrs":{}},{"type":"text","text":" 环节提问或直接问负责人。但是这是一个复杂的话题,因为讨论 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 对 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 能支持到什么程度我们也不清楚,每一个 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 版本中涉及到:语言特性(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"the language features","attrs":{}}],"attrs":{}},{"type":"text","text":")、字节码(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"the bytecode","attrs":{}}],"attrs":{}},{"type":"text","text":")、工具(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"the tools","attrs":{}}],"attrs":{}},{"type":"text","text":")、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"APIs","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"JVM","attrs":{}}],"attrs":{}},{"type":"text","text":" 以及其它方面。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当人们谈论起 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 对 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 的支持通常指的是语言特性,所以接下来让我们一起开始看看 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 的工具链是如何处理支持 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 语言特性的。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1. Lambda","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 中最大的语言特性变动是增加了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Lambda","attrs":{}}],"attrs":{}},{"type":"text","text":",相比以前使用更冗长的构造(如匿名类),","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 带来了一个更简洁的代码格式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class Java8 {\n interface Logger {\n void log(String s);\n }\n\n public static void main(String... args) {\n sayHi(s -> System.out.println(s));\n }\n\n private static void sayHi(Logger logger) {\n logger.log(\"Hello!\");\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"javac","attrs":{}}],"attrs":{}},{"type":"text","text":" 指令编译为字节码后,然后通过 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dx","attrs":{}}],"attrs":{}},{"type":"text","text":" 工具编译打包为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dex","attrs":{}}],"attrs":{}},{"type":"text","text":" 文件,但是出错了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"$ javac *.java\n\n$ ls\nJava8.java Java8.class Java8$Logger.class\n\n$ $ANDROID_HOME/build-tools/28.0.2/dx --dex --output . *.class\nUncaught translation error: com.android.dx.cf.code.SimException:\n ERROR in Java8.main:([Ljava/lang/String;)V:\n invalid opcode ba - invokedynamic requires --min-sdk-version >= 26\n (currently 13)\n1 error; aborting\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这是因为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 使用了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"invokedynamic","attrs":{}}],"attrs":{}},{"type":"text","text":" 字节码指令,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"invokedynamic","attrs":{}}],"attrs":{}},{"type":"text","text":" 是在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 7","attrs":{}}],"attrs":{}},{"type":"text","text":" 中引入的。上面的错误信息提示,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 支持这种字节码的最低版本是 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"26","attrs":{}}],"attrs":{}},{"type":"text","text":"。与此同时 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"desugaring","attrs":{}}],"attrs":{}},{"type":"text","text":"(脱糖)兼容所有 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API","attrs":{}}],"attrs":{}},{"type":"text","text":" 版本上使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 表达式。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2. Desugaring(脱糖)的历史","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"脱糖工具的发展史非常出彩,但是它的核心目标却是一致的:让所有的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 语言新特性都能运行在所有设备上。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://github.com/luontola/retrolambda","title":"","type":null},"content":[{"type":"text","text":"Retrolambda","attrs":{}}]},{"type":"text","text":" 是最初支持 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 表达式的第三方工具库,它通过在编译时利用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"JVM","attrs":{}}],"attrs":{}},{"type":"text","text":" 指令将 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 转换为内部类来实现。然而生成的类会使方法数激增,但是随着时间的推移,使用该工具的成本降低到了合理的水平。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然后,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 工具团队宣布了一个新的编译器,它将提供 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 语言特性的支持,以及更好的性能。该工具是建立在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Eclipse Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 编译器上的,而不是 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Dalvik Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 字节码之上的。虽然处理 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 效率很高,但是它的体验很差以及无法与别的工具兼容。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最终新的编译器被舍弃,同时在 ","attrs":{}},{"type":"link","attrs":{"href":"https://android-developers.googleblog.com/2017/04/java-8-language-features-support-update.html","title":"","type":null},"content":[{"type":"text","text":"Android Gradle plugin","attrs":{}}]},{"type":"text","text":" 中引入了谷歌定制的字节码构建系统,因为脱糖是增量式的,所以脱糖的输出效率仍然不是很理想,与此同时,正在进行的工作有了更好的方案。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://android-developers.googleblog.com/2017/08/next-generation-dex-compiler-now-in.html","title":"","type":null},"content":[{"type":"text","text":"D8","attrs":{}}]},{"type":"text","text":" 编译工具问世了。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 编译工具用来替代老的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dx","attrs":{}}],"attrs":{}},{"type":"text","text":" 工具,同时在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 中集成了脱糖,以此取代脱糖作为一个独立的字节码转换模块的方式。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 相比较 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dx","attrs":{}}],"attrs":{}},{"type":"text","text":" 有很大的提升,带来了更有效率的字节码转换。同时在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android Gradle Plugin 3.1","attrs":{}}],"attrs":{}},{"type":"text","text":" 中作为默认 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dex","attrs":{}}],"attrs":{}},{"type":"text","text":" 编译器,然后在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"3.2","attrs":{}}],"attrs":{}},{"type":"text","text":" 版本中 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 又集成了脱糖。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3. D8","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 工具编译上面的例子成功了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"$ java -jar d8.jar \\\n --lib $ANDROID_HOME/platforms/android-28/android.jar \\\n --release \\\n --output . \\\n *.class\n\n$ ls\nJava8.java Java8.class Java8$Logger.class classes.dex\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同时我们可以通过 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 提供的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dexdump","attrs":{}}],"attrs":{}},{"type":"text","text":" 工具来查看 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dex","attrs":{}}],"attrs":{}},{"type":"text","text":" 文件内容,看看 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 是如何脱糖的,由于 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dexdump","attrs":{}}],"attrs":{}},{"type":"text","text":" 会产生很多代码,我们只截取一部分。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"$ $ANDROID_HOME/build-tools/28.0.2/dexdump -d classes.dex\n[0002d8] Java8.main:([Ljava/lang/String;)V\n0000: sget-object v0, LJava8$1;.INSTANCE:LJava8$1;\n0002: invoke-static {v0}, LJava8;.sayHi:(LJava8$Logger;)V\n0005: return-void\n\n[0002a8] Java8.sayHi:(LJava8$Logger;)V\n0000: const-string v0, \"Hello\"\n0002: invoke-interface {v1, v0}, LJava8$Logger;.log:(Ljava/lang/String;)V\n0005: return-void\n…\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"main","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法中,对应 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"0000","attrs":{}}],"attrs":{}},{"type":"text","text":" 位置创建了一个 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java8$1","attrs":{}}],"attrs":{}},{"type":"text","text":" 类对象 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"INSTANCE","attrs":{}}],"attrs":{}},{"type":"text","text":" 实例,但是我们的源文件中并不包含这个类,所以猜测这个类是由脱糖产生的。同时 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"main","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法的字节码中也没有包含任何 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 的实现,所以很可能是在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java8$1","attrs":{}}],"attrs":{}},{"type":"text","text":" 中实现的。在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"0002","attrs":{}}],"attrs":{}},{"type":"text","text":" 位置,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"INSTANCE","attrs":{}}],"attrs":{}},{"type":"text","text":" 调用了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"sayHi","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法,同时可以看到 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"sayHi","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法的参数是 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"LJava8$Logger","attrs":{}}],"attrs":{}},{"type":"text","text":" ,所以基本可以确定 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java8$1","attrs":{}}],"attrs":{}},{"type":"text","text":" 类实现了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 中的接口。我们可以输出字节码进行验证。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Class #2 -\n Class descriptor : 'LJava8$1;'\n Access flags : 0x1011 (PUBLIC FINAL SYNTHETIC)\n Superclass : 'Ljava/lang/Object;'\n Interfaces -\n #0 : 'LJava8$Logger;'\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"SYNTHETIC","attrs":{}}],"attrs":{}},{"type":"text","text":" 字节码标签代表着这个类是由系统产生,通过 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Interfaces","attrs":{}}],"attrs":{}},{"type":"text","text":" 可以看到 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"LJava8$1","attrs":{}}],"attrs":{}},{"type":"text","text":" 类实现了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"LJava8$Logger","attrs":{}}],"attrs":{}},{"type":"text","text":" 接口。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"现在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"LJava8$1","attrs":{}}],"attrs":{}},{"type":"text","text":" 的实现已经替代了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":",我们可以通过查看 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"sayHi","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法的字节码实现。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"…\n[00026c] Java8$1.log:(Ljava/lang/String;)V\n0000: invoke-static {v1}, LJava8;.lambda$main$0:(Ljava/lang/String;)V\n0003: return-void\n…\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"sayHi","attrs":{}}],"attrs":{}},{"type":"text","text":" 的字节码实现中,它调用了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java8","attrs":{}}],"attrs":{}},{"type":"text","text":" 类中的静态方法 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda$main$0","attrs":{}}],"attrs":{}},{"type":"text","text":",但是我们并没有在类中定义这个方法,所以我们只能查看下 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java8","attrs":{}}],"attrs":{}},{"type":"text","text":" 类对应的字节码。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"…\n #1 : (in LJava8;)\n name : 'lambda$main$0'\n type : '(Ljava/lang/String;)V'\n access : 0x1008 (STATIC SYNTHETIC)\n[0002a0] Java8.lambda$main$0:(Ljava/lang/String;)V\n0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream;\n0002: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V\n0005: return-void\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在这里我们通过 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SYNTHETIC","attrs":{}}],"attrs":{}},{"type":"text","text":" 标签可以确定 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda$main$0","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法是由系统自动生成的,并且看到了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 实现的方法体 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"System.out.println","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过上面的流程分析,我们可以推测出:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 的实现保持在原来的主类中,并且是私有的,别的类无法直接访问。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4. Source Transformation(源码模拟实现)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为了更好的理解脱糖是如何工作的,我们可以在源码的层面模拟实现,注意这里的模拟仅仅是为了加深理解,脱糖实际工作比这个要复杂的多。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class Java8 {\n interface Logger {\n void log(String s);\n }\n\n public static void main(String... args) {\n sayHi(s -> System.out.println(s));\n }\n\n private static void sayHi(Logger logger) {\n logger.log(\"Hello!\");\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"第一步","attrs":{}},{"type":"text","text":"将 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 表达式移到同级的包私有方法。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" public static void main(String... args) {\n- sayHi(s -> System.out.println(s));\n+ sayHi(s -> lambda$main$0(s));\n }\n+\n+ static void lambda$main$0(String s) {\n+ System.out.println(s);\n+ }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"第二步","attrs":{}},{"type":"text","text":"生成一个内部类实现 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Logger","attrs":{}}],"attrs":{}},{"type":"text","text":" 接口,并且它的方法体调用刚才实现的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" public static void main(String... args) {\n- sayHi(s -> lambda$main$0(s));\n+ sayHi(new Java8$1());\n }\n@@\n }\n+\n+class Java8$1 implements Java8.Logger {\n+ @Override public void log(String s) {\n+ Java8.lambda$main$0(s);\n+ }\n+}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"最后","attrs":{}},{"type":"text","text":",因为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法并没有依赖外部的任何类,所以我们在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java8$1","attrs":{}}],"attrs":{}},{"type":"text","text":" 内部创建一个单例对象来避免每次调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法都生成一个新对象。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" public static void main(String... args) {\n- sayHi(new Java8$1());\n+ sayHi(Java8$1.INSTANCE);\n }\n@@\n class Java8$1 implements Java8.Logger {\n+ static final Java8$1 INSTANCE = new Java8$1();\n+\n @Override public void log(String s) {\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最终我们经过脱糖生成的文件适用与所有 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"APIs","attrs":{}}],"attrs":{}},{"type":"text","text":" 。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class Java8 {\n interface Logger {\n void log(String s);\n }\n\n public static void main(String... args) {\n sayHi(Java8$1.INSTANCE);\n }\n\n static void lambda$main$0(String s) {\n System.out.println(s);\n }\n\n private static void sayHi(Logger logger) {\n logger.log(\"Hello!\");\n }\n}\n\nclass Java8$1 implements Java8.Logger {\n static final Java8$1 INSTANCE = new Java8$1();\n\n @Override public void log(String s) {\n Java8.lambda$main$0(s);\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"实际上你在查看 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 表达式生成的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Dalvik","attrs":{}}],"attrs":{}},{"type":"text","text":" 字节码时可能看到不是类似 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":" Java8$1","attrs":{}}],"attrs":{}},{"type":"text","text":" 的名称,而是像这样的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"-$$Lambda$Java8$QkyWJ8jlAksLjYziID4cZLvHwoY","attrs":{}}],"attrs":{}},{"type":"text","text":" 名称,这是由于命名规范不恰当引起的。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5. Native Lambdas","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上面我们通过 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dx","attrs":{}}],"attrs":{}},{"type":"text","text":" 工具编译 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dex","attrs":{}}],"attrs":{}},{"type":"text","text":" 文件时,错误信息提示我们最低的支持版本是 API 26。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"$ $ANDROID_HOME/build-tools/28.0.2/dx --dex --output . *.class\nUncaught translation error: com.android.dx.cf.code.SimException:\n ERROR in Java8.main:([Ljava/lang/String;)V:\n invalid opcode ba - invokedynamic requires --min-sdk-version >= 26\n (currently 13)\n1 error; aborting\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以如果我们在使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 的时候指定 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"--min-api 26","attrs":{}}],"attrs":{}},{"type":"text","text":" 版本,应该就不会报错了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"$ java -jar d8.jar \\\n --lib $ANDROID_HOME/platforms/android-28/android.jar \\\n --release \\\n --min-api 26 \\\n --output . \\\n *.class\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同样为了查看 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 如何工作,我们还是查看 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java8","attrs":{}}],"attrs":{}},{"type":"text","text":" 类的字节码。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"$ javap -v Java8.class\nclass Java8 {\n public static void main(java.lang.String...);\n Code:\n 0: invokedynamic #2, 0 // InvokeDynamic #0:log:()LJava8$Logger;\n 5: invokestatic #3 // Method sayHi:(LJava8$Logger;)V\n 8: return\n}\n…\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为了阅读方便我只截取了部分代码,但是我们同样可以在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"main","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法中看到这里使用了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"InvokeDynamic","attrs":{}}],"attrs":{}},{"type":"text","text":" 指令,在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Code","attrs":{}}],"attrs":{}},{"type":"text","text":" 表的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"0","attrs":{}}],"attrs":{}},{"type":"text","text":" 位置上,我们可以看到第二个参数是 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"0","attrs":{}}],"attrs":{}},{"type":"text","text":",对应着 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"bootstrap method(引导方法)","attrs":{}}],"attrs":{}},{"type":"text","text":"。 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"bootstrap method","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"(引导方法)是当字节码第一次执行时首先被执行的一小段代码。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"…\nBootstrapMethods:\n 0: #27 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(\n Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;\n Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;\n Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)\n Ljava/lang/invoke/CallSite;\n Method arguments:\n #28 (Ljava/lang/String;)V\n #29 invokestatic Java8.lambda$main$0:(Ljava/lang/String;)V\n #28 (Ljava/lang/String;)V\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上面的代码中,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"bootstrap method","attrs":{}}],"attrs":{}},{"type":"text","text":"(引导方法)对应的是 ","attrs":{}},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html","title":"","type":null},"content":[{"type":"text","text":"java.lang.invoke.LambdaMetafactory","attrs":{}}]},{"type":"text","text":" 类中的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"metafactory","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"LambdaMetafactory","attrs":{}}],"attrs":{}},{"type":"text","text":" 类在运行时为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 表达式生成匿名类,而 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 是在编译时生成。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果我们查看 ","attrs":{}},{"type":"link","attrs":{"href":"https://developer.android.com/reference/java/lang/invoke/package-summary","title":"","type":null},"content":[{"type":"text","text":"Android documentation for java.lang.invoke ","attrs":{}}]},{"type":"text","text":" 和 ","attrs":{}},{"type":"link","attrs":{"href":"https://android.googlesource.com/platform/libcore/+/master/ojluni/src/main/java/java/lang/invoke/","title":"","type":null},"content":[{"type":"text","text":"AOSP source code for java.lang.invoke","attrs":{}}]},{"type":"text","text":" 的文档,我们可以注意到这个类在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android Runtime","attrs":{}}],"attrs":{}},{"type":"text","text":" 中不存在,这也是为什么脱糖在编译时要求最小版本的原因。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"VM","attrs":{}}],"attrs":{}},{"type":"text","text":" 环境支持 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"invokedynamic","attrs":{}}],"attrs":{}},{"type":"text","text":" 指令,但是 JDK 在编译 LambdaMetafactory 中却不可用。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"6. Method References(方法引用)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 表达式,方法引用也是 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 的语言特性,当 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 的实现是一个已经存在的方法,此时使用方法引用会很方便。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" public static void main(String... args) {\n- sayHi(s -> System.out.println(s));\n+ sayHi(System.out::println);\n }\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这与 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"javac","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dexes","attrs":{}}],"attrs":{}},{"type":"text","text":" 与 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 的编译是相同的,与 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 版本有一个显著的区别。在编译为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dalvik","attrs":{}}],"attrs":{}},{"type":"text","text":" 字节码时,生成的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 类的主体已更改。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"[000268] -$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM.log:(Ljava/lang/String;)V\n0000: iget-object v0, v1, L-$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM;.f$0:Ljava/io/PrintStream;\n0002: invoke-virtual {v0, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V\n0005: return-void\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不是通过生成 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java8.lambda$main$0","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法然后调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"System.out.println","attrs":{}}],"attrs":{}},{"type":"text","text":" 的方式实现,而是直接调用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"System.out.println","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 表达式调用类也不是一个静态单例,而是直接使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"PrintStream","attrs":{}}],"attrs":{}},{"type":"text","text":" 类实例引用,即 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"System.out","attrs":{}}],"attrs":{}},{"type":"text","text":",它的调用如下。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"[0002bc] Java8.main:([Ljava/lang/String;)V\n0000: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream;\n0003: new-instance v0, L-$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM;\n0004: invoke-direct {v0, v1}, L-$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM;.:(Ljava/io/PrintStream;)V\n0008: invoke-static {v0}, LJava8;.sayHi:(LJava8$Logger;)V\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同样我们也可以在源码级层面进行模拟。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" public static void main(String... args) {\n- sayHi(System.out::println);\n+ sayHi(new -$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM(System.out));\n }\n@@\n }\n+\n+class -$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM implements Java8.Logger {\n+ private final PrintStream ps;\n+\n+ -$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM(PrintStream ps) {\n+ this.ps = ps;\n+ }\n+\n+ @Override public void log(String s) {\n+ ps.println(s);\n+ }\n+}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"7. Interface Methods(接口中的方法)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 中新增了接口方法中的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"default","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"static","attrs":{}}],"attrs":{}},{"type":"text","text":" 修饰符。接口中的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"static","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法允许直接操作调用。接口中的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"default","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法允许你为接口添加默认实现方法。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"interface Logger {\n void log(String s);\n\n default void log(String tag, String s) {\n log(tag + \": \" + s);\n }\n\n static Logger systemOut() {\n return System.out::println;\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 中的脱糖都已经支持了这两个接口的新特性。通过上面的方法同样可以分析出脱糖是如何进行优化工作的,具体的分析就留给读者了。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"8. Just Use Kotlin?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这个时候肯定有很多读者猜想 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Kotlin","attrs":{}}],"attrs":{}},{"type":"text","text":" 是否也具备这种能力。当然,Kotlin 同样提供了 lambda 和接口中的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"static","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"default","attrs":{}}],"attrs":{}},{"type":"text","text":" 方法。这些特性都被 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"kotlinc","attrs":{}}],"attrs":{}},{"type":"text","text":" 以相同的方式实现。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 工具和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"VM","attrs":{}}],"attrs":{}},{"type":"text","text":" 的开发者肯定会 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"100%","attrs":{}}],"attrs":{}},{"type":"text","text":" 支持 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Kotlin","attrs":{}}],"attrs":{}},{"type":"text","text":" 实现 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 语言的新特性。因为每次的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 新版本都会在字节码构建和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"VM","attrs":{}}],"attrs":{}},{"type":"text","text":" 上带来新的优化体验。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在未来和可能 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Kotlin","attrs":{}}],"attrs":{}},{"type":"text","text":" 不会支持 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 6","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 7","attrs":{}}],"attrs":{}},{"type":"text","text":",","attrs":{}},{"type":"link","attrs":{"href":"https://blog.jetbrains.com/idea/2015/12/intellij-idea-16-eap-144-2608-is-out/","title":"","type":null},"content":[{"type":"text","text":"Intellij 开发工具已经在在 2016 年 1 月迁移至 Java 8","attrs":{}}]},{"type":"text","text":"。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"9. Desugaring APIs","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面的分析中,我们一直关注的是 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 语言新特性,其它还有一些主要的方面没有提及,比如新的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"APIs","attrs":{}}],"attrs":{}},{"type":"text","text":"。在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 转给你带来了很多新的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"APIs","attrs":{}}],"attrs":{}},{"type":"text","text":",比如 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"stream","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Optional","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"CompletableFuture","attrs":{}}],"attrs":{}},{"type":"text","text":" 以及新的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"date/time API","attrs":{}}],"attrs":{}},{"type":"text","text":" 等等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"回到上面的例子,我们使用新的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"date/time API","attrs":{}}],"attrs":{}},{"type":"text","text":" 来输出日志打印的时间。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"import java.time.*;\n\nclass Java8 {\n interface Logger {\n void log(LocalDateTime time, String s);\n }\n\n public static void main(String... args) {\n sayHi((time, s) -> System.out.println(time + \" \" + s));\n }\n\n private static void sayHi(Logger logger) {\n logger.log(LocalDateTime.now(), \"Hello!\");\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们同样使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"javac","attrs":{}}],"attrs":{}},{"type":"text","text":" 指令和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"d8","attrs":{}}],"attrs":{}},{"type":"text","text":" 指令进行编译:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"$ javac *.java\n\n$ java -jar d8.jar \\\n --lib $ANDROID_HOME/platforms/android-28/android.jar \\\n --release \\\n --output . \\\n *.class\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当编译完成后,我们可以将它运行在一个手机或模拟器中。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"$ adb push classes.dex /sdcard\nclasses.dex: 1 file pushed. 0.5 MB/s (1620 bytes in 0.003s)\n\n$ adb shell dalvikvm -cp /sdcard/classes.dex Java8\n2018-11-19T21:38:23.761 Hello\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果我们的设备运行在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API26","attrs":{}}],"attrs":{}},{"type":"text","text":" 或更高的版本上我们会得到一个带有时间戳的日志。但是在一个低于 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API26","attrs":{}}],"attrs":{}},{"type":"text","text":" 的机器上,得到确实异常信息。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"java.lang.NoClassDefFoundError: Failed resolution of: Ljava/time/LocalDateTime;\n at Java8.sayHi(Java8.java:13)\n at Java8.main(Java8.java:9)\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"显然,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 通过脱糖使 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"lambda","attrs":{}}],"attrs":{}},{"type":"text","text":" 表达式能够运行在所有的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API","attrs":{}}],"attrs":{}},{"type":"text","text":" 版本机器上,但是却没有对新 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API","attrs":{}}],"attrs":{}},{"type":"text","text":" 做任何处理,所以我们无法使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"LocalDateTime","attrs":{}}],"attrs":{}},{"type":"text","text":" 类。也说明我们仅仅能够利用部分的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 新特性,而不是全部。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"针对这种情况,开发者可自行编译组件引用或使用相关的第三方实现库来解决,但是退一步讲,既然开发者可以自己编译或实现,为什么 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 不能在脱糖中为我们做这些呢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其实 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 现在仅仅针对 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Throwable.addSuppressed","attrs":{}}],"attrs":{}},{"type":"text","text":" 这个 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API","attrs":{}}],"attrs":{}},{"type":"text","text":" 进行实现,这个 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API","attrs":{}}],"attrs":{}},{"type":"text","text":" 是用于 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 7","attrs":{}}],"attrs":{}},{"type":"text","text":" 引入的语言特性 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"try-with-resources","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们需要 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8 API","attrs":{}}],"attrs":{}},{"type":"text","text":" 在所有设备上工作,我们所需要的只是 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 团队在他们的脱糖工具中添加支持来进行重写。您可以在 ","attrs":{}},{"type":"link","attrs":{"href":"https://issuetracker.google.com/issues/114481425","title":"","type":null},"content":[{"type":"text","text":"Android 问题跟踪程序","attrs":{}}]},{"type":"text","text":"上添加 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 功能请求,以传达您的支持。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"10. 总结","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"虽然一段时间以来,语言特性的脱糖已经以各种形式出现,但是缺乏对新 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API","attrs":{}}],"attrs":{}},{"type":"text","text":" 的适配仍然是我们生态系统中的一个巨大缺陷。不然直到绝大多数应用程序能够指定最小 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API 26","attrs":{}}],"attrs":{}},{"type":"text","text":" 的那一天,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 工具链缺少 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API","attrs":{}}],"attrs":{}},{"type":"text","text":" 的缺陷才算停止阻碍 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 库生态系统的发展。尽管现在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 语言特性脱糖是 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 的一部分,但默认情况下它没有启用。开发人员必须明确地选择它们的源代码和目标兼容性到 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 库的作者可以通过使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 字节码来构建和发布它们的库(即使你不使用语言特性)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 正在积极工作,因此 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 对 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 语言和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API","attrs":{}}],"attrs":{}},{"type":"text","text":" 支持的前景仍然光明。即使你仅仅是一个 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"KOTLIN","attrs":{}}],"attrs":{}},{"type":"text","text":" 用户,重要的是要保持对 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Android","attrs":{}}],"attrs":{}},{"type":"text","text":" 的活力,以支持更好的字节码和新 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"API","attrs":{}}],"attrs":{}},{"type":"text","text":" 的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java","attrs":{}}],"attrs":{}},{"type":"text","text":" 新版本。在某些情况下,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"D8","attrs":{}}],"attrs":{}},{"type":"text","text":" 实际上是超越 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Java 8","attrs":{}}],"attrs":{}},{"type":"text","text":" 版本的,我们将在下一篇文章中进行探索。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章