Jdk1.8新特性
- Lambda表示式:Lambda 允許把函式作為一個方法的引數(函式作為引數傳遞進方法中)。可以使程式碼變的更加簡潔緊湊。
Lambda表示式的實質其實還是匿名內部類,而匿名內部類在訪問外部區域性變數時,要求變數必須宣告為final
!不過我們在使用Lambda表示式時無需宣告final
,這並不是說違反了匿名內部類的規則,因為Lambda底層會隱式的把變數設定為final
,在後續的操作中,一定不能修改該變數:
基本語法:
(引數列表) -> {程式碼塊}
需要注意:
-
引數型別可省略,編譯器可以自己推斷
-
如果只有一個引數,圓括號可以省略
-
程式碼塊如果只是一行程式碼,大括號也可以省略
-
如果程式碼塊是一行,且是有結果的表示式,
return
可以省略
注意:事實上,把Lambda表示式可以看做是匿名內部類的一種簡寫方式。當然,前提是這個匿名內部類對應的必須是介面,而且介面中必須只有一個函式!Lambda表示式就是直接編寫函式的:引數列表、程式碼體、返回值等資訊,用函式來代替完整的匿名內部類
!
用法示例
@Test public void lambdaDemo(){ //準備一個集合 List<Integer> list = Arrays.asList(1, 3, 5, 3, 1, 3, 67, 8); // 對集合進行Jdk1.7寫法,倒序和正序 Collections.sort(list,new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } }); System.out.println(list);// [-15, 5, 10, 20, 25] // Jdk1.8寫法,引數列表的資料型別可省略: lambda表示式做排序 Collections.sort(list,(Integer a,Integer b)->{ return b-a; }); System.out.println(list); // Jdk8寫法 簡潔版 // 因為程式碼塊是一個有返回值的表示式,可以省略大括號以及return Collections.sort(list,(a,b)->a-b); System.out.println(list); }
示例2:單個引數
還以剛才的集合為例,現在我們想要遍歷集合中的元素,並且列印。
jdk1.8給集合添加了一個方法:foreach()
,接收一個對元素進行操作的函式:
// JDK1.7遍歷並列印集合 for (Integer i : list) { System.out.println(i); } // JDK1.8遍歷並列印集合,因為只有一個引數,所以我們可以省略小括號: list.forEach(i -> System.out.println(i));
Lambda表示式的實質其實還是匿名內部類,所以我們其實可以把Lambda表示式賦值給某個變數。
-
Lambda表示式是介面的匿名內部類的簡寫形式
-
介面必須滿足:內部只有一個函式
-
其實這樣的介面,我們稱為函式式介面,我們學過的
Runnable
、Comparator
都是函式式介面的典型代表。但是在實踐中,函式介面是非常脆弱的,只要有人在接口裡新增多一個方法,那麼這個介面就不是函式介面了,就會導致編譯失敗。Java 8提供了一個特殊的註解@FunctionalInterface
來克服上面提到的脆弱性並且顯示地表明函式介面。而且jdk8版本中,對很多已經存在的介面都添加了@FunctionalInterface
註解,例如Runnable
介面:
另外,Jdk8預設提供了一些函式式介面供我們使用:
- Function型別介面
@FunctionalInterface
public interface Function<T, R> {
// 接收一個引數T,返回一個結果R
R apply(T t);
}
Function代表的是有引數,有返回值的函式。還有很多類似的Function介面:
介面名 | 描述 |
---|---|
BiFunction<T,U,R> |
接收兩個T和U型別的引數,並且返回R型別結果的函式 |
DoubleFunction<R> |
接收double型別引數,並且返回R型別結果的函式 |
IntFunction<R> |
接收int型別引數,並且返回R型別結果的函式 |
LongFunction<R> |
接收long型別引數,並且返回R型別結果的函式 |
ToDoubleFunction<T> |
接收T型別引數,並且返回double型別結果 |
ToIntFunction<T> |
接收T型別引數,並且返回int型別結果 |
ToLongFunction<T> |
接收T型別引數,並且返回long型別結果 |
DoubleToIntFunction |
接收double型別引數,返回int型別結果 |
DoubleToLongFunction |
接收double型別引數,返回long型別結果 |
-
Consumer系列
@FunctionalInterface
public interface Consumer<T> {
// 接收T型別引數,不返回結果
void accept(T t);
}
-
Predicate系列
@FunctionalInterface
public interface Predicate<T> {
// 接收T型別引數,返回boolean型別結果
boolean test(T t);
}
- Supplier系列
@FunctionalInterface
public interface Supplier<T> {
// 無需引數,返回一個T型別結果
T get();
}
Streams流
新增 java.util.Stream API
把一個集合變成一個流, Lists.stream()
案例一、 對集合進行排序然後去除所有的偶數再把所有數*2
這些個所有操作只經過一次遍歷,
@Test
public void streamLambdaDemo03() {
// 對集合進行排序然後去除所有的偶數再把所有數*2
List<Integer> list = Arrays.asList(1, 3, 5, 3, 1, 3, 67, 8);
//過濾偶數(傳入一個引數然後返回一個引數)
list.stream().filter(i-> i%2!=0)// 列印 1,3,5,3,1,3,67
//把集合中的每個資料用函式處理
.map(i->i*2) // 列印 2,6,10,6,2,6,134
//排序
.sorted((i1,i2)->i1-i2) // 列印 2,2,6,6,6,10,134
//JDK1.8遍歷並列印集合
.forEach(i-> System.out.println(i));
list.stream()
//加上parallel()方法還可以使這個流多執行緒處理極大的提高效率
.parallel()
.filter(i -> { System.out.println(Thread.currentThread().getName());
return i % 2 != 0; })// 列印 1,3,5,3,1,3,67
//把集合中的每個資料用函式處理
.map(i -> {
System.out.println(Thread.currentThread().getName());
return i * 2;
}) // 列印 2,6,10,6,2,6,134
//排序
.sorted((i1, i2) -> {
System.out.println(Thread.currentThread().getName());
return i1 - i2;
}) // 列印 2,2,6,6,6,10,134
//JDK1.8遍歷並列印集合
.forEach(i -> System.out.println(i));
}