2014年3月18日發(fā)布了JavaSE 8
不追求技術(shù)的新,追求技術(shù)的穩(wěn)定
本質(zhì):Lambda 表達(dá)式是一個匿名函數(shù)
作用:簡化代碼,增強(qiáng)代碼的表達(dá)力
Lambda 語法格式
// 格式1:無參無返回值 () -> System.out.println("Hello World!"); // 格式2:有參無返回值 (x) ->
System.out.println(x); // 格式3:有參有返回值 (x) -> x * x; // 格式4:多參有返回值 (x, y) -> x +
y; // 格式5:函數(shù)體包含多條語句 (x, y) -> { System.out.println("加法運(yùn)算"); return x + y; }
Lambda 表達(dá)式中的參數(shù)的數(shù)據(jù)類型可以省略,JVM 編譯器能夠根據(jù)上下文推算出,即“類型推斷”
兩個例子
/** 1. Comparator **/ TreeSet<Integer> ts1 = new TreeSet<>(new
Comparator<Integer>(){ @Override public int compare(Integer i1, Integer i2) {
return Integer.compare(i1, i2); } }); // lambda 表達(dá)式 TreeSet<Integer> ts2 = new
TreeSet<>((i1, i2) -> { return Integer.compare(i1, i2); }); //
等同于(使用方法引用還可以再次簡化) TreeSet<Integer> ts3 = new TreeSet<>((i1, i2) ->
Integer.compare(i1, i2)); /** 2. Runnable */ Thread t1 = new Thread(new
Runnable(){ @Override public void run() { System.out.println("當(dāng)前線程:" +
Thread.currentThread().getName()); } }); // lambda 表達(dá)式 Thread t2 = new
Thread(() -> { System.out.println("當(dāng)前線程:" + Thread.currentThread().getName());
});
函數(shù)式接口
!!Lambda 表達(dá)式需要函數(shù)式接口的支持
函數(shù)式接口:接口只有一個抽象方法
可以使用注解 @FunctionalInterface 修飾接口,檢查是否是函數(shù)式接口
// 定義函數(shù)式接口 @FunctionalInterface public interface Calculator<T> { public T
calculate(T x, T y); } // 使用函數(shù)式接口 Calculator<Integer> calculatorAdd = (x, y) ->
x + y; Integer result = calculatorAdd.calculate(3, 5);
Java 內(nèi)置了四大核心函數(shù)式接口:
消費(fèi)型接口 Consumer<T>:消費(fèi)一個參數(shù)對象
@FunctionalInterface public interface Consumer<T> { void accept(T t); ... }
供給型接口 Supplier<T>:返回一個對象
@FunctionalInterface public interface Supplier<T> { T get(); }
函數(shù)型接口 Function<T, R>:傳遞一個參數(shù),返回一個值
@FunctionalInterface public interface Function<T, R> { R apply(T t); ... }
斷定型接口 Predicate<T>:判斷參數(shù)是否滿足約束
@FunctionalInterface public interface Predicate<T> { boolean test(T t); ... }
對于Java內(nèi)置函數(shù)式接口建議結(jié)合 stream 方法理解,在這里了解即可
除了這4大核心函數(shù)式接口外,還有由它們延伸出的一些變種,比如二元消費(fèi)型接口 BiConsumer<T, U>
public interface BiConsumer<T, U> { void accept(T t, U u); ... }
方法引用
將 lambda 體代碼封裝為方法,然后方法引用,再次簡化代碼。
方法引用格式:類名::方法名 或 對象::方法名
溫馨提示:
實(shí)際上,在開發(fā)工具 IDEA 中,會自動提示使用方法引用簡化代碼,你只需按 ALT+Eenter 快捷鍵,根據(jù)提示選擇操作即可
如果你想要深入了解方法引用的使用原則,可以繼續(xù)往下看。(即使不看也沒大問題,有開發(fā)工具幫你優(yōu)化)
使用方法引用改寫 Comparator 例子中的 lambda 表達(dá)式
// TreeSet<Integer> ts3 = new TreeSet<>((i1, i2) -> Integer.compare(i1, i2));
// 使用方法引用 TreeSet<Integer> ts4 = new TreeSet<>(Integer::compare);
(第一種情況)實(shí)現(xiàn)函數(shù)式接口方法的參數(shù)列表,必須和方法引用方法的參數(shù)列表保持一致
即 Comparator.compare(o1, o2) 的 o1, o2 與 Integer.compare(i1, i2) 中的 i1, i2
對應(yīng),所以才能夠使用方法應(yīng)用。
當(dāng)函數(shù)式接口方法只有一個參數(shù)時(小例子):
@Test public void test3() { List<String> stringList = Arrays.asList("北京",
"天津", "上海"); // `Consumer.accept(t)` 的參數(shù) t 與 `System.out.println(o)` 的 o 對應(yīng)
show(System.out::println, stringList); } // 自定義一個函數(shù) void show(Consumer<String>
consumer, List<String> list) { for (String s : list) { consumer.accept(s); } }
還有第二種情況
TreeSet<Integer> ts3 = new TreeSet<>((i1, i2) -> i1.compareTo(i2)); // 使用方法引用
TreeSet<Integer> ts4 = new TreeSet<>(Integer::compareTo);
Comparator.compare(o1, o2) 的 o1, o2 與 i1.compareTo(i2) 中 i1, i2 對應(yīng),這樣也能使用方法引用。
(第二種情況)假設(shè)函數(shù)式接口方法參數(shù)有 (x1, x2),而方法實(shí)現(xiàn)是 x1.fun(x2) 這種形式,照樣使用方法引用
如果理解了它們的規(guī)律,推而廣之,可以試試抽象方法含有三個參數(shù)的情況。
準(zhǔn)備工作:找一個三參數(shù)的函數(shù)式接口
@Test public void test4() { String s = "Hello World"; Integer start = 0;
Integer length = 5; String r1 = consume((o1, o2, o3) -> { return
o1.substring(o2, o3); }, s, start, length); System.out.println(r1); String r2 =
consume(String::substring, s, start, length); System.out.println(r2); } String
consume(TripleFunction<String, Integer, Integer, String> tripleFunction, String
s, Integer start, Integer length) { return tripleFunction.apply(s, start,
length); } // 自定義三參數(shù)函數(shù)式接口 @FunctionalInterface interface TripleFunction<T, U,
E, R> { R apply(T t, U u, E e); }
這里 函數(shù)式接口 TripleFunction 的抽象方法 apply(T t, U u, E e)中的參數(shù) t, u, e 與
s.substring(start, length) 中的 s,start, length 對應(yīng)
小結(jié):
設(shè)函數(shù)式接口抽象方法 abstractFun(n1, n2, n3, ..., nn) ,
有方法fun(n1, n2, n3, ..., nn) 或 n1.fun(n2, n3, ..., nn) 實(shí)現(xiàn)了 lambda 體的代碼功能
就可使用方法引用 ClassName::fun
構(gòu)造器引用
用法:
Function<Integer, MyClass> fun1 = (i) -> new MyClass(i); // 使用構(gòu)造器引用
Function<Integer, MyClass> fun2 = MyClass::new; Function<Integer, Integer[]>
fun3 = (n) -> new Integer[n]; // 使用構(gòu)造器引用 Function<Integer, Integer[]> fun4 =
Integer[]::new;
函數(shù)式接口方法參數(shù)列表,必須和構(gòu)造函數(shù)參數(shù)列表一致 (和方法應(yīng)用的第一種情況相同)
熱門工具 換一換