Java8的新特性有哪些

新特性的特征:
速度更快
代碼更少(增加了新的語法:Lambda 表達式)
強大的 Stream API
便於並行
最大化減少空指針異常:Optional
Nashorn引擎,允許在JVM上運行JS應用
lambda表達式
什么是lambda表達式?
Lambda 是一個匿名函數,我們可以把 Lambda 表達式理解為是一段可以
傳遞的代碼(將代碼像數據一樣進行傳遞)。使用它可以寫出更簡潔、更 靈活的代碼。作為一種更緊湊的代碼風格,使Java的語言表達能力得到了
提升
為什么要有lambda表達式?
Lambda表達式。它可以讓你很簡潔地表示一個行為或傳遞代碼。現在你可以把Lambda 表達式看作匿名功能,它基本上就是沒有聲明名稱的方法,但和匿名類一樣,它也可以作為參 數傳遞給一個方法。
哪些場景可以使用到lambda表達式?
?????
首先我們看下再沒有使用lambda的時候使用匿名內部類的對比
lambda與匿名內部類對比
//匿名內部類 Comparator<Integer> c1 = new Comparator<Integer>() { @Override public int compare(Integer t1, Integer t2) { return Integer.compare(t1,t2); } }; int compareNumOne = c1.compare(12,13); System.out.println(compareNumOne); //-1 System.out.println("==========Lambda=========="); // lambda表達式 Comparator<Integer> c2 = (c3,c4) -> Integer.compare(c3,c4); int compareNumTwo = c2.compare(11,10); System.out.println(compareNumTwo); // 1
可以看出lambda表達式簡潔了很多,直接了,不像以前這么難懂 還有一大堆的內部邏輯
匿名內部類
Button button = new Button("Send");
button.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
label.setText("Sent!!");
}
});
這里,setOnAction方法的行為就用EventHandler參數化了。用Lambda表達式的話,看 起來就是這樣:
button.setOnAction((ActionEvent event) -> label.setText("Sent!!"));
上面可以看出lambda使用起來很方便的 簡單明了
lambda的使用
lambda的結構

參數列表——這里它采用了Comparator中compare方法的參數,兩個Apple。 箭頭——箭頭->把參數列表與Lambda主體分隔開。 Lambda主體——比較兩個Apple的重量。表達式就是Lambda的返回值了。
1.舉例: (o1,o2) -> Integer.compare(o1,o2); * 2.格式: * -> :lambda操作符 或 箭頭操作符 * ->左邊:lambda形參列表 (其實就是接口中的抽象方法的形參列表) * ->右邊:lambda體 (其實就是重寫的抽象方法的方法體)
Lambda 表達式:在Java 8 語言中引入的一種新的語法元素和操 作符。這個操作符為 “->” ,該操作符被稱為 Lambda 操作符 或箭頭操作符。
它將 Lambda 分為兩個部分:
左側:指定了 Lambda 表達式需要的參數列表
右側:指定了 Lambda 體,是抽象方法的實現邏輯,也即 Lambda 表達式要執行的功能。
下面給出了Java 8中五個有效的Lambda表達式的例子

Lambda表達式的使用(分六種)
| 語法格式一:無參,無返回值 | Runnable r1 = () -> {System.out.println("Hello Lambda");}; r1.run(); |
| 語法格式二:Lambda需要一個參數,但是沒有返回值 | Consumer<String> con = (String s) -> {System.out.println(s);}; con.accept("value"); |
| 語法格式三:數據類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷” | Consumer<String> con = (s) -> {System.out.println(s);}; con.accept("value"); |
| 語法格式四:Lambda若只需要一個參數,參數的小括號可以省略 | Consumer<String> con = s -> {System.out.println(s);}; con.accept("value"); |
| 語法格式五:Lambda需要兩個以上的參數,多條執行語句,並且可以有返回值 | Consumer<Integer> con = (x,y) -> { System.out.println(x); return x.compareTo(y); } |
| 語法格式六:當Lambda體只有一條語句時,return與大括號 |
Comparator<Integer> com = (o1, o2) -> o1.compareTo(o2); com.compreTo(10,13); |
// 語法格式一:無參,無返回值 @Test public void TestPOne(){ Runnable r1 = new Runnable() { @Override public void run() { System.out.println(" I'm one"); } }; r1.run(); System.out.println("=======lambda======"); Runnable r2 = () -> System.out.println("I'm lambda'One"); r2.run(); } // 語法格式二:Lambda 需要一個參數,但是沒有返回值。 @Test public void TestTwo(){ Consumer<String> con1 = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; con1.accept("老王"); System.out.println("=======lambda======"); Consumer<String> con2 = (String s1) -> {System.out.println(s1);}; con2.accept("我是lambda老王"); } //語法格式三:數據類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷” // 類型推斷想我們之前遇到的泛型和數組一樣 /* Consumer<String> con = new Consumer<>(); // 省略后面的String類型 int [] len = new int [] {1,2,3}; 可以 寫成 int [] len = {1,2,3} */ @Test public void TestThree(){ Consumer<String> con = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; con.accept("老王頭"); System.out.println("=======lambda======"); Consumer<String> con1 = (s) -> { System.out.println(s); }; con1.accept("吾乃lambda老王頭"); } //語法格式四:Lambda 若只需要一個參數時,參數的小括號可以省略 @Test public void TestFour(){ Consumer<String> con = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; con.accept("老劉"); System.out.println("=======lambda======"); Consumer<String> con1 = s -> {System.out.println(s);}; con1.accept("吾乃lambda老劉"); } //語法格式五:Lambda 需要兩個或以上的參數,多條執行語句,並且可以有返回值 @Test public void TestFive(){ Comparator<Integer> com = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); } }; System.out.println(com.compare(13, 14)); System.out.println("=======lambda======"); Comparator<Integer> com1 = (l1,l2) -> { System.out.println(l1); System.out.println(l2); return l1.compareTo(l2); }; System.out.println(com1.compare(11, 10)); } //語法格式六:當 Lambda 體只有一條語句時,return 與大括號若有,都可以省略 @Test public void TestSix(){ // 原有 Comparator<Integer> com = (o1, o2) -> {return o1.compareTo(o2);}; System.out.println(com.compare(10, 11)); //優化后 Comparator<Integer> com1 = (l1, l2) -> l1.compareTo(l2); System.out.println(com1.compare(20, 10)); }
由上可以看出lambda只是修改了 以前寫法的方法體 方法后面的執行和參數的傳遞依舊時不變的 只需要看方法體怎么改變即可。
Summary
* 3. Lambda表達式的使用:(分為6種情況介紹) * * 總結: * ->左邊:lambda形參列表的參數類型可以省略(類型推斷);如果lambda形參列表只有一個參數,其一對()也可以省略 * ->右邊:lambda體應該使用一對{}包裹;如果lambda體只有一條執行語句(可能是return語句),省略這一對{}和return關鍵字 * * 4.Lambda表達式的本質:作為函數式接口的實例 * * 5. 如果一個接口中,只聲明了一個抽象方法,則此接口就稱為函數式接口。我們可以在一個接口上使用 @FunctionalInterface 注解, * 這樣做可以檢查它是否是一個函數式接口。 * * 6. 所以以前用匿名實現類表示的現在都可以用Lambda表達式來寫。
函數式接口
什么是函數式接口
只包含一個抽象方法的接口,稱為函數式接口。
為什么要有函數式接口
Java從誕生日起就是一直倡導“一切皆對象”,在Java里面面向對象(OOP) 編程是一切。但是隨着python、scala等語言的興起和新技術的挑戰,
Java不 得不做出調整以便支持更加廣泛的技術要求,也即java不但可以支持OOP還 可以支持OOF(面向函數編程)
說白了 函數式接口就是為了讓java能面向函數編程而創建的
函數式接口的作用
用函數式接口可以干什么呢?Lambda表達式允許你直接以內聯的形式為函數式接口的抽象方法提供實現,並把整個表達式作為函數式接口的實例(具體說來,是函數式接口一個具體實現 的實例)
你可以通過 Lambda 表達式來創建該接口的對象。(若 Lambda 表達式 拋出一個受檢異常(即:非運行時異常),那么該異常需要在目標接口的抽 象方法上進行聲明)。
我們可以在一個接口上使用 @FunctionalInterface 注解,這樣做可以檢 查它是否是一個函數式接口。同時 javadoc 也會包含一條聲明,說明這個 接口是一個函數式接口。
在java.util.function包下定義了Java 8 的豐富的函數式接口
簡單的說,在Java8中,Lambda表達式就是一個函數式接口的實例。這就是 Lambda表達式和函數式接口的關系。也就是說,
只要一個對象是函數式接口 的實例,那么該對象就可以用Lambda表達式來表示。
所以以前用匿名實現類表 示的現在都可以用Lambda表達式來寫。

自定義函數式接口
只需要在自定義的接口上加入 @FunctionalInterface 注解即可讓這個接口成為函數事接口
@FunctionalInterface public interface MyInterface { public void method1(); }
自定義函數接口與Lambda的使用


Java 內置四大核心函數式接口

其它接口

Lambda與函數式接口的使用
// 根據傳遞參數輸出信息 public void happyTime(double money, Consumer<Double> con){ con.accept(money); } //根據給定的規則,過濾集合中的字符串。此規則由Predicate的方法決定 public List<String> filterString(List<String> list, Predicate<String> pre){ List<String> filterList = new ArrayList<>(); for (String s:list ) { if(pre.test(s)){ // 如果參數s滿足定義的Predicate的String泛型 filterList.add(s); } } return filterList; } @Test public void TestMonday(){ happyTime(500, new Consumer<Double>() { @Override public void accept(Double aDouble) { System.out.println("去隔壁洗浴中心消費"+aDouble); } }); System.out.println("=====lambda===="); happyTime(4000, money -> System.out.println("買了大寶劍花費"+money)); } @Test public void TestTuesday(){ List<String> list = Arrays.asList("老王", "老張頭","隔壁老王","隔壁小姐姐"); List<String> list1 = filterString(list, new Predicate<String>() { @Override public boolean test(String s) { return s.contains("老"); // 包含老的字符串 } }); System.out.println(list1); List<String> list2 = filterString(list,s -> s.contains("老") ); System.out.println(list2); }
lambda與方法搭配使用必須滿足函數式接口的要求,
下面既不是接口種的方法

Practices
1:

(1) 這個Lambda沒有參數,並返回void。它類似於主體為空的方法:public void run() {}。 (2) 這個Lambda沒有參數,並返回String作為表達式。 (3) 這個Lambda沒有參數,並返回String(利用顯式返回語句)。 (4) return是一個控制流語句。要使此Lambda有效,需要使花括號,如下所示: (Integer i) -> {return "Alan" + i;}。 (5)“Iron Man”是一個表達式,不是一個語句。要使此Lambda有效,你可以去除花括號 和分號,如下所示:(String s) -> "Iron Man"。或者如果你喜歡,可以使用顯式返回語 句,如下所示:(String s)->{return "IronMan";}。
2: 下面哪些接口是函數式接口?
public interface Adder{ int add(int a, int b); } public interface SmartAdder extends Adder{ int add(double a, double b); } public interface Nothing{ }
答案:只有Adder是函數式接口。 SmartAdder不是函數式接口,因為它定義了兩個叫作add的抽象方法(其中一個是從 Adder那里繼承來的)。 Nothing也不是函數式接口,因為它沒有聲明抽象方法。
.
