lambda用法
1、函數式接口
- 函數式接口用@FunctionalInterface註解標註的接口類,lambda必須和函數式接口的抽象函數描述一樣的參數類型。
- 一個接口類只包含一個抽象方法,這個接口爲函數式接口。(jdk8之後可以再接口類中聲明其他方法,需要在方法前面添加default,即默認方法。)
- 關於函數式接口第一個條件:
-
- 如果一個接口只有一個抽象方法,那麼這個接口是一個函數式接口;
-
- 如果我們在某個接口上聲明瞭FunctionalInterface接口,如果不滿足函數式 接口的要求,則會報錯;
-
- 如果某個接口只有一個抽象方法,但是我們並沒有給該接口聲明FunctionalInterface註解,這個時候,編譯器還是會將此接口視爲函數式接口。
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
- 可以使用lambda接口實現Converter接口
Converter<String, Integer> converter = (param) -> Integer.valueOf(param);
Integer result = converter.convert("101");
System.out.println(result);
new Thread(() -> System.out.println("hello lambda)).start();
2、方法引用
- 方法引用是lambda表達式的一個簡化方法。語法結構爲:
ObjectRef::methodName
2.1、靜態方法引用
public class ReferenceTest {
public static void main(String[] args) {
Converter<String, Integer> converter = ReferenceTest::String2Int;
System.out.println(converter.convert("110"));
}
static Integer String2Int(String from) {
return Integer.valueOf(from);
}
}
2.2、實例方法引用
Helper helper = new Helper();
Converter<String, Integer> converter = helper::String2Int;
System.out.println(converter.convert("120"));
3、Stream
3.1、stream簡介
- stream是一個可以對個序列中的元素執行各種計算操作的一個元素序列。下例爲鏈式調用將中間操作串聯起來。
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("a1", "a2", "b1", "b2", "c1", "c2"));
list.stream().filter(s -> s.startsWith("c")).map(String::toUpperCase).sorted().forEach(System.out::println);
}
- stream包含中間和最終兩種形式的操作。
- 中間操作返回值是一個stream,最終操作只能返回void或者一個非stream的結果。如filter,map,sorted是中間操作,forEach是最終操作。
- 方法接口的行爲基本上都是無干擾和無狀態。無干擾爲該方法不修改stream的底層數據源;無狀態爲操作的執行是獨立的。
3.2、streams分類
- 可以從不同的數據源創建stream。Collections、Lists、Sets這些類中新增stream()(順序stream)和parallelStream()(併發stream)方法。
- List對象上調用stream()方法可以返回一個常規的對象流。
Arrays.asList("a1", "a2", "a3")
.findFirst().ifPresent(System.out::println);
- 可以直接用stream創建一個collection。使用Stream.of()方法就能從一組對象創建一個stream對象。
Stream.of("a1", "a2", "a3")
.findFirst().ifPresent(System.out::println);
- IntStream、LongStream、DoubleStream可以處理基本類型:int、long、double。可以用range()方法替換掉for循環。
IntStream.range(1, 4).forEach(System.out::println);
Arrays.stream(new int[] {1,2,3})
.map(n -> 2 * n + 1)
.average()
.ifPresent(System.out::println);
)
- 可以通過常規對象流的mapToInt()、mapToObj()等方法完成常規流與基本類型流的互相轉換。
IntStream.range(1, 4).mapToObj(i -> "a" + i).forEach(System.out::println);
3.3、處理順序
- Laziness(延遲加載)是中間操作的一個重要特性。
4、爲何需要使用lambda表達式
- 在java中,我們無法將函數作爲參數傳遞給一個方法,也無法聲明返回一個函數的方法;
- 在JavaScript中,函數參數是一個函數,返回值是另一個函數的情況是非常常見的。JavaScript是一種非常典型的函數式語言。
- 同爲面嚮對象語言。
5、lambda表達式結構
5.1、lambda表達式基本結構
(param1, param2, param3) -> {
}
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
list.forEach(integer -> sout(integer));
list.forEach(System.out::println);
6、lambda表達式作用
- lambda表達式爲java添加了確實的函數式編程特性;
- 在將函數作爲一等公民的語言當中,lambda表達式的類型是函數。**但在java中,lambda表達式是對象,**他們必須依附於一類特別的對象類型-函數式接口(functionalInterface)。