(一)lambda表示式
學習記錄《寫給大忙人的java_SE8》。
先上一個我們平時用到的集合排序:這裡提供了4種方法
List<String> list = new ArrayList<>(); list.add("new world"); list.add("hello"); //匿名內部類 Collections.sort(list, new Comparator<String>() { @Override public int compare(String o1, String o2) { return Integer.compare(o1.length(), o2.length()); } }); //常規lambda Collections.sort(list, (s1, s2) -> s1.compareToIgnoreCase(s2)); //lambda方法引用 Collections.sort(list, String::compareToIgnoreCase); //Comparator介面靜態方法+方法引用 Collections.sort(list, Comparator.comparing(String::length)); list.forEach(System.out::println);
1.1 語法
引數+箭頭+表示式
例如:
Comparator<? super String> com=(String s1,String s2)->Integer.compare(s1.length(),s2.length());
a,如果沒有引數,使用()
b,如果不是一個簡單表示式可以解決的,用{}將表示式程式碼包裹起來
c,引數有時可以省略型別(見上圖),程式會自動推斷型別,建議還是寫上,方便閱讀
d,引數可以使用final等修飾,也可以使用註解修飾
1.2 函式式介面
定義:只含一個【抽象】方法的介面。任何一個lambda表示式都可以轉換成使用的API中對應的函式式介面。
物件和類的管理完全依賴於如何實現,比傳統的內部類效率高。
雖然Object是所有類的基類,但它不是函式式介面。
1.3 方法引用
a,類::靜態方法 b,物件::例項方法 上面2種等價於使用引數的lambda表示式 c,類::例項方法 上面第一個引數成為呼叫方法的物件如String::compareToIgnoreCase等價於x.compareToIgnoreCase(y)
1.4 構造器引用
格式:類名::new
List<String> labels = new ArrayList<>(); Stream<Button> stream = labels.stream().map(Button::new); Button[] buttons = stream.toArray(Button[]::new);
如上,陣列構造器引用可以繞過java中的一個限制:不能使用(new)泛型陣列(泛型擦除)
可以看到,傳入Button陣列構造器引用,返回一個Button陣列,而用list.toArray等方法返回的是Object陣列
1.5 變數作用域 lambda表示式構成:一段程式碼;引數;【自由變數的值】:自由指的是不是引數又沒有在表示式中定義的變數 lambda表示式可以捕獲閉包(含有自由變數的程式碼塊)中的變數值,需要遵守一個約束:被引用的變數的值不可以被更改(執行緒安全考慮) java8之前,內部類只允許訪問final的區域性變數,為了適應lambda表示式,規則放寬為:可以訪問任何【有效】final的區域性變數,即值不會發生改變的變數(應該是編譯期檢查) 同時注意,不要指望編譯器捕獲所有併發訪問錯誤,不可變約束只作用在區域性變數上,如果是例項或靜態變數,編譯器不會報錯。 lambda表示式中的this關鍵詞和其他地方意義一樣。
1.6 預設方法 如果一個類有多個父類/實現介面,而父類/介面中的方法名和引數衝突 a,如果父類提供具體實現,實現的介面中預設方法會被忽略(類優先原則,向後相容性) b,如果只實現2個或多個介面,它們的某個方法的方法名和引數都衝突。如果一個介面提供的是預設方法,不管其他介面是抽象還是預設方法,此類必須覆蓋這個方法;
1.7 靜態方法
java8也開啟了介面靜態方法的大門。比如Collections的nCopies方法如果放進List中,就可以使用List直接呼叫此方法,而不用Collections了。
前面提到過靜態方法,如
Comparator.comparing(String::length)
這種方式返回一個比較器是很簡潔的。