この記事では、まず、明記してくださいblog.zhaochunqi.com再現に登場blog.zhaochunqi.com
よるとJSR 335、Javaは最終的にJavaの8のラムダ式を導入しました。また、閉鎖または匿名関数を知られています。
JSR 335
いわゆるJSR(Javaの仕様要求)フルネームはJava仕様の提案と呼ばれています。これは単にJavaコミュニティに新たな提案のAPIまたはサービス要求を提出しています。これらの提案は、開発の方向性を導くために、需要Java言語Javaコミュニティとして開発されます。
提案のJSR 335内容は以下のとおりです:
このJSRは、次の機能をサポートするためのJavaプログラミング言語仕様とJava仮想マシン仕様を拡張します。
- ラムダ式
- SAMの変換
- メソッドリファレンス
- 仮想拡張メソッド
それは次のとおりです。
- ラムダ式のサポート。
- 前方互換性のためにSAM変換サポート。
- メソッドは、メソッドリファレンスを参照します
- 仮想拡張メソッド
Javaの8では、上記のすべての上記を以下に紹介され、達成されました。
なぜラムダ式?
ラムダ式、実際には、コードブロック。
元に対処する方法
特定の知識ラムダ前に、我々はこれらのコードブロックに対処する方法を見て前のは、バックステップを見てみましょう!
の例
決定は別のスレッドでプログラムを実行するときに、あなたはそう
class Worker implements Runnable { public void run() { for (int i = 0; i < 1000; i++) doWork(); } ... }
このような実行:
Worker w = new Worker();
new Thread(w).start();
労働者は、実行したいコードのブロックが含まれています。
ジカルボン酸の例
あなたは、文字列の長さの大きさではなく、デフォルトのアルファベット順に従ってソート達成したい場合は、コンパレータのソートのためにそれを自分で行うことができます。
class LengthComparator implements Comparator<String> { public int compare(String first, String second) { return Integer.compare(first.length(), second.length()); } } Arrays.sort(strings, new LengthComparator());
3の例
別の例として、私は、クリックイベント、同じJavaでのAndroidを選びました:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) { Toast.makeText(MainActivity.this, "Hello World!", Toast.LENGTH_SHORT).show(); } });
上記のコードは、問題ありますか?
彼らはあまりにも複雑ああです!
上記の例は、クラスがインターフェイスを実装し、その後、パラメータとして別のメソッドに渡され、次に行うべきです。
しかし、本質的に、彼らは渡すだけで、ああのメソッドを実装するインタフェースです!クラスを作成し、あなたを呼び出すために渡される前にポジションをインスタンス化する必要があるのでしょうか?
Javaのメソッドが何気なく通り過ぎると、私が行うことができない他の言語と同様に、純粋なオブジェクト指向言語であるため、それはそうでなければなりません。
他の言語では、Javaでは、ことはできませんが、可能かもしれませんが。
一貫性と単純化のためのJavaのJavaの設計者は、Javaへこの機能を追加することを拒否しました。(これはまた、私はああ、JavaはPythonのが好きではありません好きな理由です!)
努力の年後、開発者は、最終的にはJavaプログラミングの習慣に準拠ラムダ式を発見しました!
ラムダ式の構文(シンタックス)
前述の例を考えてみましょう。
Integer.compare(first.length(), second.length())
第一及び第二のString型、Javaは強く型付けされた言語は、あなたがタイプを指定する必要があります:
(String first, String second)
-> Integer.compare(first.length(), second.length())
ノー参照してください!最初のラムダ式は生まれました!!入力、出力、明確かつ簡潔な!
なぜそれがラムダと呼ばれ、ええと、何年も前に、論理学者は、いくつかの数学の方程式の標準化された表現を算出することができるたかったが(実際には存在するが、表現することが困難である)して、彼はℷで表されます。
重新介绍一下 Java 中 Lambda 表达式的格式:
(参数) -> 表达式
多返回值
如果计算的结果并不由一个单一的表达式返回(换言之,返回值存在多种情况),使用“{}",然后明确指定返回值。
(String first, String second) -> {
if (first.length() < second.length()) return -1;
else if (first.length() > second.length()) return 1; else return 0; }
无参数
如果没有参数,则 "()"中就空着。
() -> { for (int i = 0; i < 1000; i++) doWork(); }
省略
如果参数的类型可以被推断出,则可以直接省略
Comparator<String> comp
= (first, second) // Same as (String first, String second)
-> Integer.compare(first.length(), second.length());
这里,first和second可以被推断出是 String 类型,因为 是一个 String 类型的 Comparator。
如果单个参数可以被推断出,你连括号都可以省略:
EventHandler<ActionEvent> listener = event ->
System.out.println("Thanks for clicking!");
// Instead of (event) -> or (ActionEvent event) ->
修饰符
你可以像对待其他方法一样,annotation,或者 使用 final 修饰符
(final String name) -> ...
(@NonNull String name) -> ...
永远不要定义 result 的类型,lambda 表达式总是从上下文中推断出来的:
(String first, String second) -> Integer.compare(first.length(), second.length())
注意
注意,在lambda 表达式中,某些分支存在返回值,某些不存在返回值这样的情况是不允许的。
如 (int x) -> { if (x >= 0) return 1; }
这样是非法的。
函数式接口(Functional Interfaces/SAM)
要介绍 Java 中 lambda 表达式的实现,需要知道什么是 函数式接口。
什么叫作函数式接口呢(SAM)?
函数式接口指的是只定义了唯一的抽象方法的接口(除了隐含的Object对象的公共方法), 因此最开始也就做SAM类型的接口(Single Abstract Method)。
Lambda 表达式向前兼容这些接口。
Comparable
举个例子 Array.sort:
Arrays.sort(words,
(first, second) -> Integer.compare(first.length(), second.length()));
Array.sort() 方法收到一个实现了 Comparable<String> 接口的实例。
其实可以把 Lambda 表达式想象成一个方法,而非一个对象,一个可以传入一个接口的方法。
OnClickListener
再举个例子
button.setOnClickListener(event ->
System.out.println("Thanks for clicking!"));
你看,是不是更易读了呢?
Lambda 表达式能够向前兼容这些 interfaces, 太棒了! 那 Lambda 表达式还能干什么呢?
实际上,将函数式接口转变成 lambda 表达式是你在 Java 中唯一能做的事情。
Why ?!!
在其他的语言中,你可以定义一些方便的方法类型,但在 Java 中,你甚至不能将一个Lambda表达式赋值给类型为 Object 的变量,因为 Object 变量不是一个 Functional Interface。
Java 的设计者们坚持使用熟悉的 interface 概念而不是为其引入新的 方法类型。
(这里我还要为设计者点赞!谨慎的设计,一方面降低了初学者的门槛,一方面方便了高级用户的使用。对比 python2和 python3,升级的不兼容让很多人一直停留在 python2)
Method References
能不能再简洁一点?有的时候我们所要做的事情不过是调用其他类中方法来处理事件。
button.setOnClickListener(event -> System.out.println(event));
如果这样呢?
button.setOnAction(System.out::println);
表达式 System.out::println
属于一个方法引用(method reference), 相当于 lambda 表达式 x -> System.out.println(x)
再举个例子,如果你想对字符串不管大小写进行排序,就可以这样写!
Arrays.sort(strings, String::compareToIgnoreCase)
如上所见 ::
操作符将方法名与实例或者类分隔开。总体来说,又如下的规则:
- object::instanceMethod
- Class::staticMethod
- Class::instanceMethod
值得指出的是, this
和super
关键字可以在其中使用:
class Greeter {
public void greet() { System.out.println("Hello, world!"); } }
class ConcurrentGreeter extends Greeter { public void greet() { Thread t = new Thread(super::greet); t.start(); } }
构造方法引用 Constructor References
跟上一个差不多,毕竟构造方法 也是方法啊!!不过方法名字为 new 。
但是!这个构造方法引用有一个牛逼的地方!
你知道 Array 是不能使用范型的对吧!(什么,你不知道?看看这里 http://stackoverflow.com/questions/2927391/whats-the-reason-i-cant-create-generic-array-types-in-java),你没有办法创建一个类型为 T 的 Array 。 new T[n] 将会被覆盖为 new Object[n]。
假设我们想要一个包含 buttons 的 Array。Stream interface 可以返回一个 Object array。
Object[] buttons = stream.toArray();
不不不,我们可不想要 Object。Stream 库使用 构造方法引用解决了这个问题:
Button[] buttons = stream.toArray(Button[]::new);
变量作用域
注意到我们在题目中写着 闭包(closure),实际上,闭包的定义是: 引用了自由变量的函数。
在之前,如果需要在匿名类的内部引用外部变量,需要将外部变量定义为 final ,现在有了 lambda 表达式,你不必再这么做了。但同样需要保证外部的自由变量不能在 lambda 表达式中被改变。
这是什么意思呢? 不需要定义为 final,也不能改?
其实理解起来很简单,Java 8 中,不需要定义为 final ,但你其实可以直接把他当作 final,不要试图修改它就行了。
場合でも、あなたは内部クラスを使用しますが、今は最終的のように定義する必要はありません。
参考StackOverflowのリンク:http://stackoverflow.com/questions/4732544/why-are-only-final-variables-accessible-in-anonymous-class
デフォルトメソッド
インターフェイスが追加された場合にこのようなこのコレクションに似たインタフェースとして歴史的な理由に、それは前のエラーコードが発生します。
Javaはデフォルトの実装を提供するために、デフォルトの修飾子を使用して、きっぱりとこの問題を解決するための方法をしたいです
Collectionインタフェースのソースコードのような:
default void remove() { throw new UnsupportedOperationException("remove"); }
何のオーバーライドが存在しない場合は、エラーが返されたときにUnsupportedOperationException削除このメソッドが呼び出されます。
インタフェースのstaticメソッド
Javaの8では、インターフェイスに静的メソッドを追加することができます。場合がありますあなたと同じではありませんが、その後、便宜上、今のインターフェースには、静的メソッドを持っていることができます。
参考リンク:
著者:AlexZhao
リンクします。https://www.jianshu.com/p/85affe38ce5c
出典:ジェーン・ブック
著者によって予約ジェーンブックの著作権は、いかなる形で再現されているが、承認を得るために、作者に連絡して、ソースを明記してください。