Java 8関数インタフェース、lambda式、メソッド、コンストラクタリファレンス
10756 ワード
関数インタフェースの使用背景
Javaはオブジェクト向けプログラミング言語であり、javaのすべてはオブジェクト向け(元のデータ型を除く)であることが知られています.Javaでは関数(メソッド)はクラス/オブジェクトの一部であり、単独では存在しません.C++、Javascriptなどの他の関数プログラミング言語では、個別の関数を記述し、直接呼び出すことができます.
オブジェクト向けが悪いわけではありませんが、冗長なコードを書く必要がある場合があります.簡単な例を挙げると、Runnableインスタンスを作成する必要があります.通常、匿名の内部クラスは次のように使用されます.
実はこのコードでは、実際に役に立つのは内部のrunメソッドだけで、他のコードはjavaがオブジェクトに要求しているだけです.
JAva 8関数インタフェースとlambda式は、少量のコードを書くことで上記の効果を達成することができます.
JAva 8関数インタフェース
Java 8では、抽象的なメソッドが1つしかないインタフェースを関数インタフェースと呼び、@FunctionalInterface注釈を使用してインタフェースが関数インタフェースであることを示すことができます.この注釈は必須ではありません.注釈を加えると、インタフェースに複数の抽象メソッドがある場合、コンパイルエラーが表示されます.
JAva 8関数インタフェースの最大の利点は、lambda式を使用して関数インタフェースを初期化し、匿名の内部クラススタイルの重い書き方を避けることです.
JAva 8の集合APIは書き換えられ,多くの関数インタフェースを用いた新しいストリームAPIが導入された.Java.util.functionパッケージの下には、Consumer、Supplier、Function、Predicateなどの多くの関数インタフェースが定義されています.
Lambda式
lambda式によりjavaのオブジェクト向けに関数式プログラミングをイメージ化できます.オブジェクトはjava言語の基本であり、オブジェクトから離れて単独で使用することはできません.これもjavaがlambda式を提供して関数式インタフェースしか使用できない理由です.
抽象的な方法が1つしかない場合、lambda式を使用すると困惑することはありません.Lambda式の署名:*(argument 1,argument 2,...)->(body)**(argument 1,argument 2,...)*メソッド署名、argument 1,argument 2,...パラメータリスト *->は矢印であり、方法体 を指す.(body)はメソッド体であり、{}ラップコードブロックを用いて を表すことができる.無参照メソッドの場合、メソッド署名は() を使用することができる.パラメータが1つしかない場合は、()は を省略することができる.
Runnableインスタンスを前に作成したコードは、lambda式を使用して実装できます.
このコードを説明します. Runnableは関数インタフェースなので、lambda式を使用してインスタンス を作成できます. run()メソッドにはパラメータがあるので,我々のlambda式にもパラメータ はない. if-else文のように、コードが1行しかない場合は{}記号を省くことができます.
なぜlambda式を使うのか
コード量を減らす
連続的、並列的な実行をサポート
この問題を解決するコードは連続しており,与えられた数字が大きいと時間がかかる.もう1つの欠点は、ブランチが多すぎて可読性が悪いことです.LambdaとストリーミングAPIの書き方:
IntStreamは、元のタイプintの連続並列実行をサポートする自然な順序付け要素です.よりよく読むために、コードはさらに最適化されます.
range(arg 1,arg 2)メソッドは、1つのIntStreamがarg 1を含むが、arg 2のステップ長が1でないシーケンスを返す.
noneMatch()は、要素が一致していないかどうか、所定の事前定義条件Predicateに一致しないかどうかを返します.
メソッドに動作アクションを渡す
リスト内の条件を満たす要素を合計する必要があります.
使用方法は次のとおりです.
効率的なリロード
もし私たちが3-11の間の最大の奇数を見つけて、その平方を求める必要があるならば.
このようなコードを使用することができます.
上記のコードは、1つのシーケンスで処理され、ストリームAPIを使用して代替することができます.
コロン式はメソッドの参照であり、NumberTest::isOddは(i)->isOdd(i)またはi->NumberTest.isOdd(i)の略である.
より多くのlambda式の例
メソッド、コンストラクタリファレンス
JAva 8は、コロン式を使用してメソッドを参照できます.
Javaはオブジェクト向けプログラミング言語であり、javaのすべてはオブジェクト向け(元のデータ型を除く)であることが知られています.Javaでは関数(メソッド)はクラス/オブジェクトの一部であり、単独では存在しません.C++、Javascriptなどの他の関数プログラミング言語では、個別の関数を記述し、直接呼び出すことができます.
オブジェクト向けが悪いわけではありませんが、冗長なコードを書く必要がある場合があります.簡単な例を挙げると、Runnableインスタンスを作成する必要があります.通常、匿名の内部クラスは次のように使用されます.
Runnable r = new Runnable(){
@Override
public void run() {
System.out.println("My Runnable");
}};
実はこのコードでは、実際に役に立つのは内部のrunメソッドだけで、他のコードはjavaがオブジェクトに要求しているだけです.
JAva 8関数インタフェースとlambda式は、少量のコードを書くことで上記の効果を達成することができます.
JAva 8関数インタフェース
Java 8では、抽象的なメソッドが1つしかないインタフェースを関数インタフェースと呼び、@FunctionalInterface注釈を使用してインタフェースが関数インタフェースであることを示すことができます.この注釈は必須ではありません.注釈を加えると、インタフェースに複数の抽象メソッドがある場合、コンパイルエラーが表示されます.
JAva 8関数インタフェースの最大の利点は、lambda式を使用して関数インタフェースを初期化し、匿名の内部クラススタイルの重い書き方を避けることです.
JAva 8の集合APIは書き換えられ,多くの関数インタフェースを用いた新しいストリームAPIが導入された.Java.util.functionパッケージの下には、Consumer、Supplier、Function、Predicateなどの多くの関数インタフェースが定義されています.
Lambda式
lambda式によりjavaのオブジェクト向けに関数式プログラミングをイメージ化できます.オブジェクトはjava言語の基本であり、オブジェクトから離れて単独で使用することはできません.これもjavaがlambda式を提供して関数式インタフェースしか使用できない理由です.
抽象的な方法が1つしかない場合、lambda式を使用すると困惑することはありません.Lambda式の署名:*(argument 1,argument 2,...)->(body)*
Runnableインスタンスを前に作成したコードは、lambda式を使用して実装できます.
Runnable r1 = () -> System.out.println("My Runnable");
このコードを説明します.
なぜlambda式を使うのか
コード量を減らす
lambda
連続的、並列的な実行をサポート
lambda API 。
, 。 :
, :
private static boolean isPrime(int number) {
if(number < 2) return false;
for(int i=2; iif(number % i == 0) return false;
}
return true;
}
この問題を解決するコードは連続しており,与えられた数字が大きいと時間がかかる.もう1つの欠点は、ブランチが多すぎて可読性が悪いことです.LambdaとストリーミングAPIの書き方:
private static boolean isPrime(int number) {
return number > 1
&& IntStream.range(2, number).noneMatch(
index -> number % index == 0);
}
IntStreamは、元のタイプintの連続並列実行をサポートする自然な順序付け要素です.よりよく読むために、コードはさらに最適化されます.
private static boolean isPrime(int number) {
IntPredicate isDivisible = index -> number % index == 0;
return number > 1
&& IntStream.range(2, number).noneMatch(
isDivisible);
}
range(arg 1,arg 2)メソッドは、1つのIntStreamがarg 1を含むが、arg 2のステップ長が1でないシーケンスを返す.
noneMatch()は、要素が一致していないかどうか、所定の事前定義条件Predicateに一致しないかどうかを返します.
メソッドに動作アクションを渡す
リスト内の条件を満たす要素を合計する必要があります.
public static int sumWithCondition(List numbers, Predicate predicate) {
return numbers.parallelStream()
.filter(predicate)
.mapToInt(i -> i)
.sum();
}
使用方法は次のとおりです.
//
sumWithCondition(numbers, n -> true)
//
sumWithCondition(numbers, i -> i%2==0)
// 5
sumWithCondition(numbers, i -> i>5)
効率的なリロード
もし私たちが3-11の間の最大の奇数を見つけて、その平方を求める必要があるならば.
このようなコードを使用することができます.
private static int findSquareOfMaxOdd(List numbers) {
int max = 0;
for (int i : numbers) {
if (i % 2 != 0 && i > 3 && i < 11 && i > max) {
max = i;
}
}
return max * max;
}
上記のコードは、1つのシーケンスで処理され、ストリームAPIを使用して代替することができます.
public static int findSquareOfMaxOdd(List numbers) {
return numbers.stream()
.filter(NumberTest::isOdd)
.filter(NumberTest::isGreaterThan3)
.filter(NumberTest::isLessThan11)
.max(Comparator.naturalOrder())
.map(i -> i * i)
.get();
}
public static boolean isOdd(int i) {
return i % 2 != 0;
}
public static boolean isGreaterThan3(int i){
return i > 3;
}
public static boolean isLessThan11(int i){
return i < 11;
}
コロン式はメソッドの参照であり、NumberTest::isOddは(i)->isOdd(i)またはi->NumberTest.isOdd(i)の略である.
より多くのlambda式の例
() -> {} //
() -> 42 //
() -> null //
() -> { return 42; } // ,
() -> { System.gc(); } //
//
() -> {
if (true) return 10;
else {
int result = 15;
for (int i = 1; i < 10; i++)
result *= i;
return result;
}
}
(int x) -> x+1 //
(int x) -> { return x+1; } //
(x) -> x+1 // ,
x -> x+1 //
(String s) -> s.length() //
(Thread t) -> { t.start(); } //
s -> s.length() //
t -> { t.start(); } //
(int x, int y) -> x+y //
(x,y) -> x+y //
(x, final y) -> x+y // 。 final y
(x, int y) -> x+y // ,
メソッド、コンストラクタリファレンス
JAva 8は、コロン式を使用してメソッドを参照できます.
System::getProperty
System.out::println
"abc"::length
ArrayList::new
int[]::new