1.介面改善
a.介面中可以定義靜態方法
b.更重要的是,介面中的方法,可以用default修飾後,加入方法體
2.為什麼不能用預設方法來重寫equals,hashcode,toString方法?
即介面不能提供對Object類別的任何方法的預設實作。如果一個類別實作了一個方法,那麼總是優先於預設的實作的。一旦所有介面的實例都是Object的子類,所有介面實例都已經有對equals/hashCode/toString的非預設實作。因此,一個在介面上這些的預設版本都是沒用的,它也不會被編譯。
3.函數式介面
核心概念就是函數式介面。如果一個介面定義個唯一一個抽象方法,那麼這個介面就成為函數式介面。例如,java.lang.Runnable就是一個函數式接口,因為它只定義一個抽象方法:
public abstract void run();
登入後複製
什麼是函數式接口,有兩種情況:1.接口只有一個抽象方法,abstract修飾2 .介面只有一個抽象方法,abstract修飾。同時,包含多個預設方法,因為預設方式是被default修飾,不是被abstract修飾。
同時,引進了一個新的Annotation:@FunctionalInterface。可以把他它放在一個介面前,表示這個介面是一個函數式介面。加上它的介面不會被編譯,除非你設法把它變成一個函數式介面。它有點像@Override,都是聲明了一種使用意圖,避免你把它用錯。
4.Lambdas
一個函數式介面非常有價值的屬性就是他們能夠用lambdas來實例化。這裡有一些lambdas的例子:
左邊是指定類型的逗號分割的輸入列表,右邊是帶有return的程式碼區塊:
(int x, int y) -> { return x + y; } 登入後複製
左邊是推導類型的逗號分割的輸入列表,右邊是回傳值:
左邊是推導類型的單一參數,右邊是回傳值:
左邊沒有輸入(官方名稱: "burger arrow"),在右邊回傳一個值:
左邊是推導類型的單一參數,右邊是沒回傳值的程式碼區塊(回傳void):
x -> { System.out.println(x); } 登入後複製
靜態方法引用:
非靜態方法引用:
繼承的函數參考:
建構子參考:
你可以想出一些函數引用格式作為其他lambda格式的簡寫。
## 等價的lambda表達式 String::valueOf #x -> String.valueOf(x) Object::toString ##x -> x.toString() x::toString
### ######() -> x.toString()############ArrayList::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't modify the value of count }); 登入後複製
登入後複製
例外的透明度 - 如果一个已检测的例外可能从lambda内部抛出,功能性的接口也必须声明已检测例外可以被抛出。这种例外不会散布到其包含的方法。这个代码不会被编译:
void appendAll(Iterable<String> values, Appendable out) throws IOException { // doesn't help with the error values.forEach(s -> {out.append(s); // error: can't throw IOException here // Consumer.accept(T) doesn'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't }});
} 登入後複製
登入後複製
进一步阅读关于这些问题的资料,看看这篇Brian Goetz写的说明:在 Block中响应“已验证例外”Java8有哪些新的特性
为什么抽象类不能通过利用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的方式提供。例如:
这里存在性能上的一些原因,主要释在输入或输出的时候避免装箱和拆箱操作。
你应该记住,有一些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't modify the value of count }); 登入後複製
登入後複製
例外的透明度 - 如果一个已检测的例外可能从lambda内部抛出,功能性的接口也必须声明已检测例外可以被抛出。这种例外不会散布到其包含的方法。这个代码不会被编译:
void appendAll(Iterable<String> values, Appendable out) throws IOException { // doesn't help with the error values.forEach(s -> {out.append(s); // error: can't throw IOException here // Consumer.accept(T) doesn'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't }});
} 登入後複製
登入後複製
进一步阅读关于这些问题的资料,看看这篇Brian Goetz写的说明:在 Block中响应“已验证例外”
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有哪些新的特性
翻译于 4年前
2 人顶
顶 翻译得不错哦!
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的方式提供。例如:
這裡存在著效能上的一些原因,主要釋在輸入或輸出的時候避免裝箱和拆箱操作。
Java8有哪些新的特性
#翻譯於4年前
##2
2 #人頂
頂
翻譯得不錯!
#2
#########本文中的所有譯本僅用於學習和溝通目的,轉載請務必註明文章譯者、出處、和本文連結# #####我們的翻譯工作遵照 CC 協議,如果我們的工作有侵犯到您的權益,請及時聯繫我們##################評論(## #85###)###### ########## #######
以上是Java8有哪些新的特性的詳細內容。更多資訊請關注PHP中文網其他相關文章!
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Java 8中如何計算一年前或一年後的日期?
Apr 26, 2023 am 09:22 AM
Java8計算一年前或一年後的日期利用minus()方法計算一年前的日期packagecom.shxt.demo02;importjava.time.LocalDate;importjava.time.temporal.ChronoUnit;publicclassDemo09{publicstaticvoidmain(String[]args ){LocalDatetoday=LocalDate.now();LocalDatepreviousYear=today.minus(1,ChronoUni
win7家庭版與win7旗艦版的差異介紹
Jul 12, 2023 pm 08:41 PM
大家都知道win7系統有很多種版本,像是win7旗艦版、win7專業版、win7家用版等,有不少用戶在家庭版和旗艦版之間糾結,不知道選擇哪個版本比較好,所以今天小編來跟大家說說win7家庭餐與win7旗艦版的差別介紹,大家一起來看看。 1.體驗不同家庭普通版使您的日常操作變得更快、更簡單,可以更快、更方便地存取使用最頻繁的程式和文件。家庭高級版讓您享有最佳的娛樂體驗,可以輕鬆欣賞和分享您喜愛的電視節目、照片、影片和音樂。旗艦版集各版本功能大全,具備Windows7家庭高級版的所有娛樂功能與專
掌握Spring MVC的關鍵概念:了解這些重要特性
Dec 29, 2023 am 09:14 AM
了解SpringMVC的關鍵特性:掌握這些重要的概念,需要具體程式碼範例SpringMVC是一種基於Java的Web應用開發框架,它透過模型-視圖-控制器(MVC)的架構模式來幫助開發人員建立靈活可擴展的Web應用程式。了解和掌握SpringMVC的關鍵特性將使我們能夠更有效地開發和管理我們的網路應用程式。本文將介紹一些SpringMVC的重要概念
如何使用Java 8計算一週後的日期?
Apr 21, 2023 pm 11:01 PM
Java8如何計算一週後的日期這個例子會計算一週後的日期。 LocalDate日期不包含時間訊息,它的plus()方法用來增加天、週、月,ChronoUnit類別宣告了這些時間單位。由於LocalDate也是不變型,回傳後一定要用變數賦值。 packagecom.shxt.demo02;importjava.time.LocalDate;importjava.time.temporal.ChronoUnit;publicclassDemo08{publicstaticvoidmain(String[
Golang中有類似類別的物件導向特性嗎?
Mar 19, 2024 pm 02:51 PM
在Golang(Go語言)中並沒有傳統意義上的類別的概念,但它提供了一種稱為結構體的資料類型,透過結構體可以實現類似類別的物件導向特性。在本文中,我們將介紹如何使用結構體實現物件導向的特性,並提供具體的程式碼範例。結構體的定義和使用首先,讓我們來看看結構體的定義和使用方式。在Golang中,結構體可以透過type關鍵字定義,然後在需要的地方使用。結構體中可以包含屬
選擇適用的Go版本,依需求和特性
Jan 20, 2024 am 09:28 AM
隨著網路的快速發展,程式語言也不斷演化和更新。其中,Go語言作為一種開源的程式語言,在近年來備受關注。 Go語言的設計目標是簡單、有效率、安全且易於開發和部署。它具有高並發、快速編譯和記憶體安全等特性,讓它在Web開發、雲端運算和大數據等領域中有著廣泛的運用。然而,目前Go語言也有不同的版本可供選擇。在選擇合適的Go語言版本時,我們需要考慮需求和特性兩個面向。首
5g的三個特性是什麼
Dec 09, 2020 am 10:55 AM
5g的三個特性是:1、高速率;在實際應用中,5G網路的速率是4G網路10倍以上。 2、低時延;5G網路的時延約幾十毫秒,比人的反應速度還要快。 3.廣連結;5G網路出現,配合其他技術,將會打造一個全新的萬物互聯景象。
C++ 函式的型別和特性
Apr 11, 2024 pm 03:30 PM
C++函式有以下型別:簡單函式、const函式、靜態函式、虛函式;特性包括:inline函式、預設參數、參考回傳、重載函式。例如,calculateArea函數使用π計算給定半徑圓的面積,並將其作為輸出傳回。
See all articles