variable ejemplo collection java lambda java-8 javac bytecode

ejemplo - En Java Lambda, ¿por qué se llama getClass() a una variable capturada?



java stream collect to list (1)

Sí, llamar a getClass() ha convertido en una expresión canónica de "prueba para null ", ya que se espera que getClass() sea ​​una operación intrínseca barata y, supongo, HotSpot podría detectar este patrón y reducir la operación a un null intrínseco - verificar el funcionamiento, si el resultado de getClass() no se utiliza.

Otro ejemplo es crear una instancia de clase interna con una instancia externa que no sea this :

public class ImplicitNullChecks { class Inner {} void createInner(ImplicitNullChecks obj) { obj.new Inner(); } void lambda(Object o) { Supplier<String> s=o::toString; } }

compila a

Compiled from "ImplicitNullChecks.java" public class bytecodetests.ImplicitNullChecks { public bytecodetests.ImplicitNullChecks(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return void createInner(bytecodetests.ImplicitNullChecks); Code: 0: new #23 // class bytecodetests/ImplicitNullChecks$Inner 3: dup 4: aload_1 5: dup 6: invokevirtual #24 // Method java/lang/Object.getClass:()Ljava/lang/Class; 9: pop 10: invokespecial #25 // Method bytecodetests/ImplicitNullChecks$Inner."<init>":(Lbytecodetests/ImplicitNullChecks;)V 13: pop 14: return void lambda(java.lang.Object); Code: 0: aload_1 1: dup 2: invokevirtual #24 // Method java/lang/Object.getClass:()Ljava/lang/Class; 5: pop 6: invokedynamic #26, 0 // InvokeDynamic #0:get:(Ljava/lang/Object;)Ljava/util/function/Supplier; 11: astore_2 12: return }

Ver también JDK-8073550 :

Algunos lugares en nuestra biblioteca de clase usan el extraño truco de usar object.getClass () para verificar la nulidad. Si bien esto parece un movimiento inteligente, en realidad confunde a las personas para que crean que esta es una práctica aprobada de verificación nula.

Con JDK 7, tenemos Objects.requireNonNull que proporciona la comprobación nula adecuada y declara el intento de forma adecuada.

Podría ser discutible si esto debería aplicarse también a las verificaciones intrínsecas del lenguaje de programación, ya que el uso de Objects.requireNonNull para ese propósito crearía una dependencia a una clase fuera del paquete java.lang no visible en el código fuente. Y en este caso específico, el truco solo es visible para quienes miran el código de bytes. Pero se ha decidido cambiar el comportamiento con Java 9.

Así es como jdk1.9.0b160 compila la misma clase de prueba:

Compiled from "ImplicitNullChecks.java" public class bytecodetests.ImplicitNullChecks { public bytecodetests.ImplicitNullChecks(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return void createInner(bytecodetests.ImplicitNullChecks); Code: 0: new #26 // class bytecodetests/ImplicitNullChecks$Inner 3: dup 4: aload_1 5: dup 6: invokestatic #27 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object; 9: pop 10: invokespecial #28 // Method bytecodetests/ImplicitNullChecks$Inner."<init>":(Lbytecodetests/ImplicitNullChecks;)V 13: pop 14: return void lambda(java.lang.Object); Code: 0: aload_1 1: dup 2: invokestatic #27 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object; 5: pop 6: invokedynamic #29, 0 // InvokeDynamic #0:get:(Ljava/lang/Object;)Ljava/util/function/Supplier; 11: astore_2 12: return }

Si miras el código de bytes para

Consumer<String> println = System.out::println;

el código de bytes generado por Java 8 actualización 121 es

GETSTATIC java/lang/System.out : Ljava/io/PrintStream; DUP INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class; POP INVOKEDYNAMIC accept(Ljava/io/PrintStream;)Ljava/util/function/Consumer; [ // handle kind 0x6 : INVOKESTATIC java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; // arguments: (Ljava/lang/Object;)V, // handle kind 0x5 : INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V, (Ljava/lang/String;)V ] ASTORE 1

Se getClass() método getClass() en System.out y el resultado se ignora.

¿Es esto una verificación indirecta de referencia nula?

Ciertamente si corres

PrintStream out = null; Consumer<String> println = out::println;

Esto desencadena una NullPointerException.