詳細に定義されたインタフェース機能
関数は、抽象インターフェースメソッドであります
そこに達成するためのデフォルトの方法があるので、彼らは抽象的ではありませんので。
インターフェースは抽象メソッドを定義していますが、彼はただのパブリックオブジェクトのメソッドをカバーする場合、それが最終的にどこかで実現を取得しますので、まだ、ない抽象インタフェースのメソッドを実行します。(それが公開されていない場合ので、カウント)
それは唯一の抽象メソッドのデフォルトではありません、オブジェクトがあまりにも公開されていません
機能インタフェースの例は、方法または参照コンストラクタの表現ラムダ式で参照することができます |
タイプは、インターフェイスでなければならず、他のそのようなクラスになると注釈を使用している場合、機能のインターフェイスまたはコンパイルエラーが定義された要件に準拠する必要がありますすることはできません |
かかわらず、彼らはFunctionalInterfaceに注釈を付けるためにノートを使用する必要があるかどうかの、コンパイラは、任意のインタフェース機能インタフェースもせずにOKであるインターフェースの関数として定義されていますが、明らかにそれなしで、フォローアップが増えることがあり、制限の制約はないだろう満足させます他の方法は、エラーになり |
共通のインタフェース機能
インタフェースjava.util.function四つの基本的なパッケージ
抽象メソッドをインターフェース
- 述語<T>ブーリアンテスト(T tの);
- 消費者<T>のボイドは、(T tを)受け入れます。
- 機能<T、R> R適用(T tの);
- サプライヤー<T> T)(取得します。
java.util.function.Predicate <T>
条件テスター受信状態であるアサーション、テスト
抽象インタフェースはT汎用オブジェクトを受け取り、ブール値を返すテストという名前のメソッドを定義します。
試験(試験条件)、及び - または - ネゲート(またはで)方法
java.util.function.Consumer <T>
無効データが消費される消費支出データ受信パラメータとリターン
それはTがジェネリックであるオブジェクトを受け入れ受け入れるという名前の抽象メソッドを定義し、(ボイド)返しません
あなたはタイプTのオブジェクトにアクセスし、特定のアクションを実行する必要がある場合は、このインターフェイスを使用することができます
java.util.function.Function <T、R>
入力データ変換関数の出力機能
既知のインターフェースは汎用オブジェクト戻りの一般的なターゲットT及びRをとる方法を定義適用します。
java.util.function.Supplier <T>
プロバイダは、出力データTを提供し、入力を必要としない
タイプTの引数なし設けオブジェクトとコンストラクタ
なぜ基本的なタイプの拡張機能があるはずです
自動がジェネリック型パラメータとしてのみの目的は、基本的なタイプのために、ボックス化とアンボックス化の操作に関連することができ
しかし、これは必然的に梱包、メモリのオーバーヘッドをもたらし、開梱、コストをもたらします
そのため、基本的なタイプの拡張子のこれらのタイプのパフォーマンス・オーバーヘッドを低減するために
Streamクラスの種類と作られた梱包タイプの基本的な区別のいくつかの方法
唯一のJava 8、
整数
、
長整数
、および
倍精度浮動小数点は、
それらが最も頻繁に数値計算で使用されているので、特別な処理を行います
基本的なタイプの特別な処理を行う方法が明確に名前で定義されています
- パラメータはプリミティブ型である場合だけでなく、タイプ名は接頭辞を付けることができます
- メソッドの戻り値の型がプリミティブ型である場合には、前の基本的なタイプでプラスに
それを要約すると:
プラスタイプのプレフィックス[のInt |ダブル|ロング] パラメータを表し、これに基づいて、戻り値の型を表現するために追加した場合、基本的なタイプである原始的です |
可能であれば、これのパフォーマンスを向上させること、可能な限り行われ、特別な処理の基本的な型を使用
機能インターフェースの例
機能インタフェースの例は、方法または参照コンストラクタの表現ラムダ式で参照することができます
ラムダ式
ラムダ式は、匿名関数を表すために使用されて送信されることができる簡単な匿名関数を示すの方法として理解することができます
それは名前がないが、それはパラメータのリストを持っている、主な機能は、例外リストの種類を返し、投げることができるがあるかもしれません。
機能
- 匿名 - それは、通常の方法が明確な名前を持っていないので、匿名我々は、言う:以下、はるかに欲しいを書きます!
- 機能は - 私たちは、それが特定のクラスに属するものとしてではないので、ラムダ関数法で、関数であることを言います。しかし、同じおよび方法は、ラムダは、パラメータのリスト、主な機能、戻り値の型を持っている、また、例外のリストがスローされる可能性があります。
- --Lambda発現は、メソッドへのパラメータとして渡し、または変数に格納することができます。
- シンプル - 匿名クラスなどの多くのテンプレートコードを記述する必要はありません。
基本的な構文
ラムダは、基本的な構文であります
(パラメータ) - >式 |
または(注文のブレース)
(パラメータ) - > {文。} |
三つの部分へのラムダ式
- パラメータ一覧
- 矢印( - >パラメータリストと本体ラムダから離間)
- ラムダ体(表現またはステートメント)
1.式が示すパラメータ、空の括弧を()が含まれていない、そのパラメータ() - >のSystem.out.println( "Hello World" の);
2と唯一のパラメータを含んでは括弧は、Sパラメータを省略することができる含まれています - >のSystem.out.println(「Hello Worldのを」);
本体3ラムダ式は、ブロックを囲むだけでなく、式であってもよく、また、コードのブロックであってもよい、中括弧({})
例外をスローする一般的な方法は、区別できない次のコードブロックの規則は、終了するか、または戻すために使用されてもよいです。
コードラムダ式の唯一のラインもどこどこに終了するには、[スタートするラムダ式をクリアするために括弧を使用することができます。
() - > {System.out.print( "こんにちは");System.out.println( "世界");}。
4.ラムダ式は、また、複数のパラメータを含む方法(ロングX、ロングy)を表すことができる - > X + Yを。
我々は、型推論によって、以下議論する。> X + Y - 5 4発現は、(x、y)を簡略化することができます
代わりに、変数のラムダのみ基準値(実際には、最終的な必要)
匿名内部クラスは、メソッド、変数にそれを参照する必要がある場合、変数はfinalとして宣言する必要があります
ラムダ式は、最終が、可変である必要はありません、変数が最終的に既成事実でなければなりません
最終的には一度だけ変数の代入を意味し、実際にあります。言い換えれば、引用されたラムダ式ではなく、同様の変数と匿名内部クラスの値は変更しないことが必要であるので、変数値のコピーを使用して、あります
あなたは、変数回を割り当て、その後、ラムダ式で参照しようとした場合、コンパイラはエラーになります
例えば:
すべてが正常に最終的に設定する必要が実行されていません
ハロー変数値の再割り当てすると、コンパイラはエラーを報告します
メソッドの参照
メソッドの参照は、既存の定義方法を再利用し、同じラムダとして渡すことができるように
使用方法::参照を示すために、
三つの主要なメソッドの参照があります。
(1)静的メソッドの参照方法を指す(例えば、整数::のparseIntを書き込む整数のparseInt方法として)
これは、静的メソッドは、オブジェクトに作用しています
例:値の文字列に
(2)メソッドの方法の参考例のいずれかのタイプを指し(例えば、長さの文字列方法、文字列::書き込み長さ)
プロセスでは、オブジェクトを参照し、オブジェクト自体はラムダのパラメータです。例えば、ラムダ式(文字列S) - > s.toUppeCase()は文字列:: toUpperCaseのように書くことができます。
例:(そう一緒に圧搾スペースと改行なし)印字文字列1 3 2の長さ
(3)既存のメソッドオブジェクトの基準点の例
例えば、ラムダ式のcharAt列helloStringコール()メソッドは、既存のオブジェクトhelloStringあります
例:シーケンスの指定した値でのcharAt文字列を取得します。
コンストラクタの参照
既存のコンストラクタのために、あなたはそれへの参照を作成するために、その名前と新しいキーワードを利用することができます。
クラス名::新しいです
これは、同様の静的メソッドへの参照点として機能します
定义Class A 三个属性 设置了默认值 以观察构造方法的调用情况
class A { private String s1="a"; private String s2="b"; private String s3="c"; A(){ } A(String s1){ this.s1=s1; } A(String s1,String s2){ this.s1=s1; this.s2=s2; } A(String s1,String s2,String s3){ this.s1=s1; this.s2=s2; this.s3=s3; } @Override public String toString() { final StringBuilder sb = new StringBuilder("A{"); sb.append("s1='").append(s1).append('\''); sb.append(", s2='").append(s2).append('\''); sb.append(", s3='").append(s3).append('\''); sb.append('}'); return sb.toString(); } }
可以看到分别调用了,无参构造方法 一个参数构造方法以及两个参数构造方法
如果三个构造方法如何设置呢?
我们只需要定义函数接口即可
再次运行
类型检查与类型推断
类型检查
我们知道当我们操作赋值运算时会有类型检查
比如:
那么对于函数式接口与函数值呢
函数式接口 变量名 = Lambda-匿名函数/方法引用/构造方法引用; |
那么函数作为值是如何进行类型检查的?
Lambda的类型是从使用Lambda的上下文推断出来的
上下文中Lambda表达式需要的类型称为目标类型
上下文是比如接受它传递的方法的形式参数,或接受它的值的局部变量
形式参数或者局部变量都会有类型的定义与声明
比如筛选 1~9之中小于5的数值
List<Integer> listNum = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
List filteredNum = listNum.stream().filter(i -> i.compareTo(5) <0).collect(Collectors.toList());
System.out.println(filteredNum);
这个示例中接收 Lambda表达式 作为参数的形式参数为 Predicate<? super T> predicate
也就是目标类型 函数接口为Predicate<T>
找到了目标类型 我们的T为Integer
也就是Predicate<Integer>
他的抽象方法为 boolean test(T t); 也就是 boolean test(Integer t); 接收一个Integer返回一个boolean
我们的Lambda匿名函数 i -> i.compareTo(5) < 0 就是接收一个Integer 返回一个boolean 所以类型检查通过
简单说就是:
1. 通过形参类型或者变量类型 找到函数接口进而找到抽象方法的声明
2. 然后在与参数值进行比对查看是否匹配
|
可以看得出来,Lambda表达式最终匹配的是 函数接口中的抽象方法的方法签名
如果不同的函数接口,具有相互兼容的抽象方法签名 那么一个Lambda表达式显然可以匹配多个函数接口
|
特殊的void兼容规则
如果一个Lambda的主体是一个语句表达式, 它就和一个返回void的函数描述符兼容(当然需要参数列表也兼容)。
就是说 如果主体是一个语句,不管做什么或者调用方法返回其他的类型,他都可以兼容void
|
例如
List的add方法 boolean add(E e);
List<String> list= new ArrayList<>();
// Predicate返回了一个boolean
Predicate<String> p = s -> list.add(s);
// Consumer返回了一个void
Consumer<String> b = s -> list.add(s);
上面的代码都可以通过编译,并且运行
类型推断
类型推断的概念,在Java中不是第一次出现
Java SE 7之前,声明泛型对象的代码如下
List<String> list = new ArrayList<String>(); |
Java 7中,可以使用如下代码:
List<String> list = new ArrayList<>(); |
这就是类型推断 ,一个最直接直观的好处就是可以简化代码的书写,这不就是语法糖么
针对 Lambda表达式也有类型推断
Java编译器可以根据 上下文(目标类型)推断出用什么函数式接口来配合Lambda表达式
然后就可以获取到函数接口对应的函数描述符也就是那个抽象方法的方法签名
编译器可以了解Lambda表达式的参数类型,这样就可以在Lambda语法中省去标注参数类型
比如刚才的筛选 1~9之中小于5的数值的例子中,就可以有如下几种写法
.filter((Integer i) -> { return i.compareTo(5) < 0;}).collect(Collectors.toList());
.filter((Integer i) ->i.compareTo(5) < 0).collect(Collectors.toList());
.filter(i ->i.compareTo(5) < 0).collect(Collectors.toList());