Java8新特性之Lambda表示式學習一
剛畢業入職新工作,在職崗位培訓時,老師在操作集合老使用Lambda表示式。這使一個之前完全沒有接觸過Lambda表示式的少年甚是苦惱,看不懂,閒餘時間決定搞一搞Lambda表示式到底是啥東西?底層原理怎麼實現的,接下來我將我的學習成果一起分享給大家......
一、Lambda表示式的簡介:
Lambda表示式首先不是一種新的知識點,而是Java8推出來的一種新的語法。這種新的語法背後仍然是介面、方法、引數、返回值、匿名內部類等。並且這種語法方便程式設計師編寫,但是JVM在編譯時,會自動還原以前我們自己寫的程式碼。
例1:對其學生分數進行升序排序:
public class Test { class User{ private String name; private Integer score; public User(String name, Integer score) { this.name = name; this.score = score; } @Override public String toString() { return this.name + this.score; } } /** * 傳統的寫法 */ public void testOldUse(){ User[] users = new User[]{new User("張三",80),new User("李四",81),new User("王五",82)}; //對User陣列按照score排序 Arrays.sort(users, new Comparator<User>() { public int compare(User o1, User o2) { //有可能兩個數相減,超出int範圍,所以我們借用Integer中的compare()方法 //return o1.score - o2.score; return Integer.compare(o1.score, o2.score); } }); System.out.println(Arrays.toString(users)); } /** * 使用lambda表示式 */ @Test public void testNewUse(){ User[] users = new User[]{new User("張三",83),new User("李四",84),new User("王五",85)}; //對User陣列按照score排序new Comparator<User>() { //Lambda表示式 (切記三個一定) /* 第一:Arrays.sort()這個方法的第二引數一定是實現了Comparator介面; * 第二:實現Comparator介面,一定要重寫compare()方法; * 第三:方法compare()執行完畢,一定會返回一個int型別的值; * 這些JVM在編譯的時候,會自動的幫助我們新增這些所缺的內容; */ Arrays.sort(users, (User o1, User o2) -> { return Integer.compare(o1.score,o2.score); } ); System.out.println(Arrays.toString(users)); } /** * 再次簡化lambda表示式 */ @Test public void testNewUse2(){ User[] users = new User[]{new User("張三",86),new User("李四",87),new User("王五",88)}; /* Lambda表示式 * 第一:Integer.compare()這個方法會返回一個int值; * 第二:Comparetor這個介面的compare()方法也會返回一個int值; * 第三:JVM會自動推匯出Integer.compare()這個方法返回的int值即為compare()所要返回的值,所以return可以省略; */ Arrays.sort(users, (User o1, User o2) -> Integer.compare(o1.score,o2.score)); System.out.println(Arrays.toString(users)); } /** * 最終簡化lambda表示式 */ @Test public void testNewUse3(){ User[] users = new User[]{new User("張三",89),new User("李四",90),new User("王五",91)}; /* Lambda表示式 * 第一:如果程式碼塊中只有一行程式碼, * 第二:Integer.compare()這個方法會返回一個int值; * 第三:compare()這個方法也會返回一個int值,JVM會自動推匯出Integer.compare()這個方法返回的值為compare()的值,所以return可以省略; * 第四:compare()這個方法的引數型別一定是User型別,所以JVM會推匯出要比較兩個引數的型別,可以省略User */ Arrays.sort(users, (o1,o2) -> Integer.compare(o1.score,o2.score)); System.out.println(Arrays.toString(users)); } }
實踐:大家可以自行實現lambda表示式代替匿名內部類,建立Runnable介面例項,並重寫run()方法,然後啟動執行緒!
二、Lambda表示式之變數:(Lambda表示式俗稱閉包)
(1) 介面的方法引數:Lambda表示式中()圓括號中的引數變數;
(2) 區域性變數:Lambda表示式程式碼塊中宣告的變數;
(3) 自由變數:不是引數,也不是區域性變數,是外部方法的引數變數;
例2:匿名內部類使用外部變數,該變數一定是final修改的,不可改變
//content、times即為自由變數 public void repeatprint(String content,int times) { // 第一:匿名內部類若使用外部的變數,該變數一定是使用final修飾; Runnable runnable = () -> { //若run()方法中有引數,即為介面的方法引數 int i = 0; //宣告一個區域性變數 for (; i <= times; i++) { //content = "not update"; //該變數自動被final修飾,不能修改 System.out.println(content); } //this指向的是外部類的例項,而不是內部類本身 System.out.println(this); }; new Thread(run).start(); }
注意1:匿名內部類中的this指代匿名內部類本身,而Lambda表示式中的this指代的外部類例項,即為建立Lambda表表達式方法中的this(就是外部類本身);
注意2:Lambda表示式中訪問自由變數(建立Lambda表示式方法的引數),final修飾,不可修改!
三、Lambda表示式之引數列表
(1) 如果Lambda表示式沒有引數,直接使用()來表示,()不能省略;
例3:啟動執行緒
//Lambda表示式沒有引數時,()不能省略,否則編譯出錯
public void testTread(){
new Thread(() -> System.out.println("Hello lambda")).start();
}
(2) 如果Lambda表示式只有一個引數,若沒寫了引數型別,引數外可不加();若寫了引數型別,則引數外必須加();
例4:借用Frame中的Button元件新增事件處理:
Frame f = new Frame();
f.setSize(100,100);
Button btn = new Button("lambda");
//原始方式,匿名內部類建立
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Hello lambda");
}
});
/* lambda表示式只有一個引數
* 第一:addActionListener()這個方法的引數一定是ActionListener介面的實現類例項;
* 第二:實現ActionListener介面一定要重寫actionPerformed()方法;
* 第三:重寫actionPerformed()方法,引數一定是ActionEvent型別;
* JVM會自動的幫助我們推匯出來
*/
/* 第一種方式:btn.addActionListener((ActionEvent e) -> System.out.println("Hello lambda"));
* 第二種方式:btn.addActionListener(event -> System.out.pringln("Hello lambda"));
*/
f.add(btn);
f.setVisible(true);
(3) 如果有兩個引數或多個引數,不管是否寫引數型別,一定要加();若引數要加修飾符,一定要新增完整的型別。
例5:將其字串陣列中升序排序
/**
* Lambda表示式有兩個引數
*/
public void testLambda(){
String[] strs = new String[]{"Android","IOS","Java","OS"};
Arrays.sort(strs,(s1,s2) -> Integer.compare(s1.length(), s2.length()));
/* 如果引數要加修飾符或者標籤(例如:final、static關鍵字),引數一定要加完整的型別;
* Arrays.sort(strs,(final String s1,final String s2) -> Integer.compare(s1.length(), s2.length()));
*/
System.out.println(Arrays.toString(strs));
}
雖然例子簡單,但想理解Lambda表示式如何從匿名內部類轉變而來的原理,底層實現等,需要大家揣摩和思考。繼續歡迎大家參考:Java8新特性之Lambda表示式學習二