ラムダ式(2) [Java 8]
ラムダ式に実際に渡されているオブジェクトが何であるかを調べるためのテストコードです。
このプログラムをコンパイルして実行すると、次の結果になります。
また、コンパイル結果の
ラムダ式を受け付けるメソッドとしてimport java.util.Arrays; import java.util.function.Consumer; public class Lambda02 { public static void main(String[] args) { showInfoOfLambda(msg -> System.out.println(msg)); } private static void showInfoOfLambda(Consumer<String> consumer) { consumer.accept("Hello World"); Class<?> consumerClass = consumer.getClass(); System.out.printf("class name : %s%n", consumerClass.getName()); showImplementedInterfaces(consumerClass); showSuperclass(consumerClass); } private static void showImplementedInterfaces(Class<?> consumerClass) { Class<?>[] interfaces = consumerClass.getInterfaces(); if (interfaces.length == 0) { System.out.println("no interface is implemented"); return; } System.out.print("implements : "); Arrays.asList(interfaces).forEach( cl -> System.out.printf("%s ", cl)); System.out.println(); } private static void showSuperclass(Class<?> consumerClass) { System.out.printf("superclass : %s%n", consumerClass.getSuperclass()); } }
showInfoOfLambda
メソッドを定義して、main
メソッドで引数を表示するだけのラムダ式を渡しています。showInfoOfLambda
では、最初に、Consumer
インタフェースとして渡された引数に対して、accept
メソッドを呼び出しています。次に渡されたオブジェクトのクラス、実装しているインタフェース、スーパークラスと順に表示しています。このプログラムをコンパイルして実行すると、次の結果になります。
実際に渡されているオブジェクトのクラスは、shibata-yoshiki-no-macbook:java8study yoshiki$ javac Lambda02.java shibata-yoshiki-no-macbook:java8study yoshiki$ java Lambda02 Hello World class name : Lambda02$$Lambda$1 implements : interface java.util.function.Consumer superclass : class java.lang.invoke.MagicLambdaImpl shibata-yoshiki-no-macbook:java8study yoshiki$ ls -l *.class -rw-r--r-- 1 yoshiki staff 2313 3 17 11:07 Lambda02.class shibata-yoshiki-no-macbook:java8study yoshiki$
Lambda02$$Lambda$1
、実装しているインタフェースはjava.util.function.Consumer
、スーパークラスは java.lang.invoke.MagicLambdaImpl
と表示されています。また、コンパイル結果の
.class
ファイルは、Lambda02.class
しかありません。したがって、Lambda02$$Lambda$1
は、実行時に動的に生成されていることが推測されます。
ラムダ式(1) [Java 8]
Java 8では、Java言語の仕様が大きく変わります。新たな言語仕様にキャッチアップするために学習を始めたので、メモ程度ですが、分かったことを順不同に今後書いていきたいを思います。したがって、新たな言語仕様のチュートリアルではありませんので注意してください。
ラムダ式は、現在、EarlyAccess版のOpenJDKで使用でき、以下のサイトからダウンロードできます。
http://jdk8.java.net/lambda/
Java 8では
しかし、コンパイル結果としては、
ラムダ式は、現在、EarlyAccess版のOpenJDKで使用でき、以下のサイトからダウンロードできます。
http://jdk8.java.net/lambda/
Java 8では
Iterable
インタフェースにforEach()
メソッドが追加されていますので、Iterable
インタフェースを実装しているコレクションを使用して、次のようなコードを書くことができます。import java.util.List; import java.util.ArrayList; public class Lambda01 { public static void main(String[] args) { List<String> messages = new ArrayList<>(); messages.add("Hello"); messages.add("World"); messages.forEach(msg -> System.out.printf("%s ", msg)); System.out.println(); } }
forEach()
メソッドには、引数msg
を受け取り、それを出力するという簡単なラムダ式が渡されています。コンパイルして実行した結果は、次の通りです。ここで不思議に思うのは、C:\Users\Yoshiki Shibata\Desktop\java8study>javac Lambda01.java C:\Users\Yoshiki Shibata\Desktop\java8study>java Lambda01 Hello World
forEach()
メソッドの引数の型はIterable
インタフェースではどのように定義されているかということです。調べて見ると次のようになっています(コメントは削ってあります)。インタフェースのなのにメソッドの実装が書かれていることは今回は無視して、引数の型はpackage java.lang; import java.util.Iterator; import java.util.function.Consumer; @FunctionalInterface public interface Iterable{ Iterator<T> iterator(); public default void forEach(Consumer<? super T> consumer) { for (T t : this) { consumer.accept(t); } } }
Consumer
インタフェース型となっています。Java 6までの言語仕様の知識から、「Consumber
インタフェースを実装した無名クラスをコンパイラが生成しているのでは」と単純に推測できます。しかし、コンパイル結果としては、
Lambda01.class
ファイルしか存在しません。それで、javapで調べると次のような結果となります。C:\Users\Yoshiki Shibata\Desktop\java8study>javap -p Lambda01 Compiled from "Lambda01.java" public class Lambda01 { public Lambda01(); public static void main(java.lang.String[]); private static void lambda$0(java.lang.String); }
forEach()
メソッドに渡したラムダ式の実体は、どうもこの lambda$0(java.lang.String)のようです。でも、accept
という名前でないし、一体どうやってConsumerインタフェースとして渡されているのかが不思議になります。(続く)