ホームページ  >  記事  >  Java  >  Java8の新機能は何ですか?

Java8の新機能は何ですか?

巴扎黑
巴扎黑オリジナル
2017-07-24 16:53:351478ブラウズ

1. インターフェースの改善

a. 静的メソッドをインターフェースで定義できる

b. さらに重要なのは、インターフェース内のメソッドをデフォルトで変更してメソッド本体を追加できることです

2.デフォルトのメソッドは、equals、hashcode、toString メソッドですか?

つまり、インターフェースは Object クラスのメソッドのデフォルト実装を提供できません。クラスがメソッドを実装する場合、それは常にデフォルトの実装より優先されます。すべてのインターフェイス インスタンスが Object のサブクラスになると、すべてのインターフェイス インスタンスにはすでに、equals/hashCode/toString のデフォルト以外の実装が含まれます。したがって、インターフェイス上のこれらのデフォルト バージョンは役に立たず、コンパイルされません。

3. 関数型インターフェース

中心となる概念は関数型インターフェースです。インターフェイスが単一の抽象メソッドを定義する場合、そのインターフェイスは関数インターフェイスになります。たとえば、java.lang.Runnable は抽象メソッドを 1 つだけ定義しているため、関数型インターフェイスです:

public abstract void run();
 

関数型インターフェイスとは次の 2 つの状況があります: 1. インターフェイスには抽象メソッドが 1 つだけあり、抽象的な変更が含まれています。には、抽象メソッドである抽象変更が 1 つだけあります。同時に、デフォルト メソッドは抽象ではなくデフォルトで変更されるため、複数のデフォルト メソッドが含まれています。

同時に、新しいアノテーション @FunctionalInterface が導入されました。これをインターフェイスの前に置くと、インターフェイスが機能インターフェイスであることを示すことができます。インターフェイスを関数インターフェイスに変換しない限り、インターフェイスを追加してもコンパイルできません。これは @Override に似ており、誤って使用しないように使用する意図を宣言します。

4.Lambdas

関数型インターフェイスの非常に貴重な特性は、ラムダを使用してインスタンス化できることです。以下にラムダの例をいくつか示します。

左側は指定された型のコンマ区切りの入力リスト、右側は return を含むコード ブロックです。

(int x, int y) -> { return x + y; }

左側は、指定された型のコンマ区切りの入力リストです。派生型、右側が戻り値:

(x, y) -> x + y

左側が派生型の単一パラメータ、右側が戻り値:

x -> x * x

左側には入力がありません (正式名称) : "burger arrow")、右側に値が返されます:

() -> x

左側は導出型の単一パラメータ、右側は値を返さないコードのブロック (void を返す) :

x -> { System.out.println(x); }

静的メソッドリファレンス:

String::valueOf

非静的メソッドリファレンス:

Object::toString

継承関数リファレンス:

x::toString

コンストラクタリファレンス:

ArrayList::new

いくつかの関数を思いつくことができます参照形式は他のラムダの短縮形として機能しますフォーマット。

メソッドリファレンス 同等のラムダ式
String::valueOf x -> String.valueOf(x )
Object::toString x -> rayList: :new
() -> new ArrayList()

  当然,在Java里方法能被重载。类可以有多个同名但不同参数的方法。这同样对构造方法有效。ArrayList::new能够指向它的3个构造方法中任何一个。决定使用哪个方法是根据在使用的函数式接口。

  一个lambda和给定的函数式接口在“外型”匹配的时候兼容。通过“外型”,我指向输入、输出的类型和声明检查异常。

给出两个具体有效的例子:

Comparator<String> c = (a, b) -> Integer.compare(a.length(),
                                                 b.length());

一个Comparator的compare方法需要输入两个阐述,然后返回一个int。这和lambda右侧的一致,因此这个任务是有效的。

Runnable r = () -> { System.out.println("Running!"); }

一个Runnable的run方法不需要参数也不会返回值。这和lambda右侧一致,所以任务有效。

在抽象方法的签名里的受检查异常(如果存在)也很重要。如果函数式接口在它的签名里声明了异常,lambda只能抛出受检查异常。

5.捕获和非捕获的Lanbdas表达式 

  当Lambda表达式访问一个定义在Lambda表达式体外的非静态变量或者对象时,这个Lambda表达式称为“捕获的”。比如,下面这个lambda表达式捕捉了变量x:

  int x = 5; return y -> x + y;

  为了保证这个lambda表达式声明是正确的,被它捕获的变量必须是“有效final”的。所以要么它们需要用final修饰符号标记,要么保证它们在赋值后不能被改变。

Lambda表达式是否是捕获的和性能悄然相关。一个非不捕获的lambda通常比捕获的更高效,虽然这一点没有书面的规范说明(据我所知),而且也不能为了程序的正确性指望它做什么,非捕获的lambda只需要计算一次. 然后每次使用到它都会返回一个唯一的实例。而捕获的lambda表达式每次使用时都需要重新计算一次,而且从目前实现来看,它很像实例化一个匿名内部类的实例。

6.其他

  lambdas不做的事

你应该记住,有一些lambdas不提供的特性。为了Java 8它们被考虑到了,但是没有被包括进去,由于简化以及时间限制的原因。

Non-final* 变量捕获 - 如果一个变量被赋予新的数值,它将不能被用于lambda之中。"final"关键字不是必需的,但变量必须是“有效final”的(前面讨论过)。这个代码不会被编译:

int count = 0;
List<String> strings = Arrays.asList("a", "b", "c");
strings.forEach(s -> {
    count++; // error: can&#39;t modify the value of count });

例外的透明度 - 如果一个已检测的例外可能从lambda内部抛出,功能性的接口也必须声明已检测例外可以被抛出。这种例外不会散布到其包含的方法。这个代码不会被编译:

void appendAll(Iterable<String> values, Appendable out) throws IOException { // doesn&#39;t help with the error values.forEach(s -> {out.append(s); // error: can&#39;t throw IOException here // Consumer.accept(T) doesn&#39;t allow it });}

有绕过这个的办法,你能定义自己的功能性接口,扩展Consumer的同时通过像RuntimeException之类抛出 IOException。我试图用代码写出来,但发现它令人困惑是否值得。

控制流程 (break, early return) -在上面的 forEach例子中,传统的继续方式有可能通过在lambda之内放置 "return;"来实现。但是,没有办法中断循环或者从lambda中通过包含方法的结果返回一个数值。例如:

final String secret = "foo"; boolean containsSecret(Iterable<String> values) {
    values.forEach(s -> { if (secret.equals(s)) {
            ??? // want to end the loop and return true, but can&#39;t }});
}

进一步阅读关于这些问题的资料,看看这篇Brian Goetz写的说明:在 Block中响应“已验证例外”Java8の新機能は何ですか?

 
其它翻译版本(1)

为什么抽象类不能通过利用lambda实例化

抽象类,哪怕只声明了一个抽象方法,也不能使用lambda来实例化。

下面有两个类 Ordering 和 CacheLoader的例子,都带有一个抽象方法,摘自于Guava 库。那岂不是很高兴能够声明它们的实例,像这样使用lambda表达式?

Ordering order = (a, b) -> ...;

CacheLoader<String, String> loader = (key) -> ...;

这样做引发的最常见的争论就是会增加阅读lambda的难度。以这种方式实例化一段抽象类将导致隐藏代码的执行:抽象类的构造方法。

另一个原因是,它抛出了lambda表达式可能的优化。在未来,它可能是这种情况,lambda表达式都不会计算到对象实例。放任用户用lambda来声明抽象类将妨碍像这样的优化。

外,有一个简单地解决方法。事实上,上述两个摘自Guava 库的实例类已经证明了这种方法。增加工厂方法将lambda转换成实例。

 

Ordering<String> order = Ordering.from((a, b) -> ...);
CacheLoader<String, String> loader = CacheLoader.from((key) -> ...);

要深入阅读,请参看由 Brian Goetz所做的说明: response to "Allow lambdas to implement abstract classes"。

 

java.util.function

包概要:java.util.function

作为Comparator 和Runnable早期的证明,在JDK中已经定义的接口恰巧作为函数接口而与lambdas表达式兼容。同样方式可以在你自己的代码中定义任何函数接口或第三方库。

但有特定形式的函数接口,且广泛的,通用的,在之前的JD卡中并不存在。大量的接口被添加到新的java.util.function 包中。下面是其中的一些:

  • Function -T作为输入,返回的R作为输出

  • Predicate -T作为输入,返回的boolean值作为输出

  • Consumer - T作为输入,执行某种动作但没有返回值

  • Supplier - 没有任何输入,返回T

  • BinaryOperator -两个T作为输入,返回一个T作为输出,对于“reduce”操作很有用

这些最原始的特征同样存在。他们以int,long和double的方式提供。例如:

  • IntConsumer -以int作为输入,执行某种动作,没有返回值

这里存在性能上的一些原因,主要释在输入或输出的时候避免装箱和拆箱操作。

 
 
 

你应该记住,有一些lambdas不提供的特性。为了Java 8它们被考虑到了,但是没有被包括进去,由于简化以及时间限制的原因。

Non-final* 变量捕获 - 如果一个变量被赋予新的数值,它将不能被用于lambda之中。"final"关键字不是必需的,但变量必须是“有效final”的(前面讨论过)。这个代码不会被编译:

int count = 0;
List<String> strings = Arrays.asList("a", "b", "c");
strings.forEach(s -> {
    count++; // error: can&#39;t modify the value of count });

例外的透明度 - 如果一个已检测的例外可能从lambda内部抛出,功能性的接口也必须声明已检测例外可以被抛出。这种例外不会散布到其包含的方法。这个代码不会被编译:

void appendAll(Iterable<String> values, Appendable out) throws IOException { // doesn&#39;t help with the error values.forEach(s -> {out.append(s); // error: can&#39;t throw IOException here // Consumer.accept(T) doesn&#39;t allow it });}

有绕过这个的办法,你能定义自己的功能性接口,扩展Consumer的同时通过像RuntimeException之类抛出 IOException。我试图用代码写出来,但发现它令人困惑是否值得。

控制流程 (break, early return) -在上面的 forEach例子中,传统的继续方式有可能通过在lambda之内放置 "return;"来实现。但是,没有办法中断循环或者从lambda中通过包含方法的结果返回一个数值。例如:

final String secret = "foo"; boolean containsSecret(Iterable<String> values) {
    values.forEach(s -> { if (secret.equals(s)) {
            ??? // want to end the loop and return true, but can&#39;t }});
}

进一步阅读关于这些问题的资料,看看这篇Brian Goetz写的说明:在 Block中响应“已验证例外”

Java8の新機能は何ですか?
Java8の新機能は何ですか?
翻译于 4年前
4人顶
 翻译得不错哦!
 
其它翻译版本(1)

为什么抽象类不能通过利用lambda实例化

抽象类,哪怕只声明了一个抽象方法,也不能使用lambda来实例化。

下面有两个类 Ordering 和 CacheLoader的例子,都带有一个抽象方法,摘自于Guava 库。那岂不是很高兴能够声明它们的实例,像这样使用lambda表达式?

Ordering order = (a, b) -> ...;

CacheLoader<String, String> loader = (key) -> ...;

这样做引发的最常见的争论就是会增加阅读lambda的难度。以这种方式实例化一段抽象类将导致隐藏代码的执行:抽象类的构造方法。

另一个原因是,它抛出了lambda表达式可能的优化。在未来,它可能是这种情况,lambda表达式都不会计算到对象实例。放任用户用lambda来声明抽象类将妨碍像这样的优化。

外,有一个简单地解决方法。事实上,上述两个摘自Guava 库的实例类已经证明了这种方法。增加工厂方法将lambda转换成实例。

 

Ordering<String> order = Ordering.from((a, b) -> ...);
CacheLoader<String, String> loader = CacheLoader.from((key) -> ...);

要深入阅读,请参看由 Brian Goetz所做的说明: response to "Allow lambdas to implement abstract classes"。

Java8の新機能は何ですか?
Java8の新機能は何ですか?
翻译于 4年前
2人顶
 翻译得不错哦!
 

java.util.function

パッケージの概要: java.util.function

Comparator と Runnable の初期の証明として、JDK で既に定義されているインターフェイスは、たまたま関数インターフェイスとしてラムダ式と互換性があります。同様に、独自のコードで関数インターフェイスやサードパーティ ライブラリを定義できます。

しかし、広範囲かつ普遍的な、以前の JD カードには存在しなかった特定の形式の関数インターフェイスがあります。多数のインターフェースが新しい java.util.function パッケージに追加されました。その一部を次に示します:

  • Function -T を入力として、R を出力として返します

  • Predicate -T を入力として、ブール値を出力として返します

  • Consumer

  • Supplier - 入力として T を返し、出力として 1 つの T を返します。 「reduce」操作

  • これらの最も原始的な機能も存在します。これらは int、long、double として提供されます。例:

IntConsumer - int を入力として受け取り、何らかのアクションを実行し、戻り値はありません

  • ここにはパフォーマンス上の理由がいくつかありますが、主に入力または出力中のボックス化およびボックス化解除操作を回避するためです。

PMを待っていますJava8の新機能は何ですか? 4年前に翻訳
2
Peopleのトップ
トップ
良い翻訳です!
1
  • 2

  • 3

  • >

この記事のみのすべての翻訳学習とコミュニケーションを目的として、転載する際には必ず翻訳者、出典、およびこの記事へのリンクを明記してください
私たちの翻訳作業はCC規約に準拠しています。私たちの翻訳作業があなたの権利を侵害している場合は、すぐにご連絡ください
コメント (
85
)

以上がJava8の新機能は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:最初のエッセイ次の記事:最初のエッセイ