Java8 lambda函数式编程
Lambda 表達式是 Java SE8 推出的新功能,也是Java第一次引入函數式編程的嘗試。
Lambda表達式格式
Lambda 表達式可以看做是一種匿名函數,但是它沒有訪問修飾符、返回值和名字。Lambda表達式由兩部分構成,形式參數和方法體,中間用“->”符號分隔。其中的形式參數類型能夠進行自動推斷,可以不寫。當然在某些特殊情況下,形參類型也是不可缺少的。方法體可以是簡單的表達式或者代碼塊,下面是一些例子:
// 1. 不需要參數,返回值為 5
() -> 5
// 2. 接收一個參數(數字類型),返回其2倍的值
x -> 2 * x
// 3. 接受2個參數(數字),并返回他們的差值
(x, y) -> x – y
// 4. 接收2個int型整數,返回他們的和
(int x, int y) -> x + y
// 5. 接受一個 string 對象,并在控制臺打印,不返回任何值(看起來像是返回void)
(String s) -> System.out.print(s)
要理解Lambda表達式,首先要了解一種特殊的接口:函數式接口。什么是函數式接口呢?簡單來說就是只包含一個抽象方法的接口。Java標準庫中的java.lang.Runnable和java.util.Comparator就是典型的函數式接口。對于函數式接口,我們就可以使用Lambda表達式來代替用傳統匿名類來創建實例對象。
java.util.function包
在Java SE8之前標準庫中的函數式接口并不多。JavaSE8增加了java.util.function包,里面都是可以在開發中只用的函數式接口。我們也可以自定義一個函數式接口,但最好在接口上使用@FunctionalInterface注解標明這是一個函數式接口,以免團隊其它成員錯誤地往接口添加新的方法,當然java.util.function包中的所有接口都添加了@FunctionalInterface注解。
函數式接口
我們以Runnable接口為例,用傳統匿名類的方式創建一個線程:
public void runThread() {
new Thread(new Runnable() {
public void run() {
System.out.println("Run!");
}
}).start();
}
上面傳統匿名類方式中,我們可以看到,我們需要new一個接口名稱,接口內部還要附帶這個接口抽象方法的實現。而如果我們使用Lambda表達式,則代碼非常簡潔:
public void runThreadUseLambda() {
new Thread(() -> {
System.out.println("Run!");
}).start();
}
通過上面代碼我們可以看到,Lambda表達式在兩方面做了簡化:
首先不需要聲明Runnable接口,因為這可以通過上下文推斷出來
其次不需要再寫一個run方法的實現,因為函數式接口中只有一個方法
---------------------
使用場景
場景:有個User的List,需要將所有的用戶ID取出來。
List<Integer> userIds = users.stream().map(u -> u.getId()).collect(Collectors.toList());
1
場景:有個User的List,需要將所有的用戶ID取出來,還得注意去重
List<Integer> userIds = users.stream().map(u -> u.getId()).distinct().collect(Collectors.toList());
1
場景:有個User的List,需要將其放到HashMap里,key為用戶ID,value為該User
Map<Integer, User> userMap = users.stream().collect(Collectors.toMap(User :: getId, u -> u));
1
場景:有個User的List,需要將其放到HashMap里,key為用戶ID,value為用戶名稱
Map<Integer, String> userMap = users.stream().collect(Collectors.toMap(User :: getId, u -> u.getName()));
1
場景:有個User的List,需要將其放到HashMap里,key為用戶ID,value為該User。User可能會重復,也就是ID會重復。按照上面的做法會導致如下錯誤:
Exception in thread "main" java.lang.IllegalStateException: Duplicate key 123456
1
/**
* 需要指定在key重復時選擇保留舊值還是新值
*/
Map<Integer, User> userMap = users.stream().collect(Collectors.toMap(User :: getId, u -> u, (oldV, newV) -> newV));
1
場景:有個User的List,需要按照id的大小進行排序
List<User> users = new ArrayList<User>();
users.sort((u1, u2) -> u1.getId().compareTo(u2.getId()));
---------------------
常用方法
stream()、將集合變成了流,
filter、過濾到我們所需要的,
collect(Collectors.toList())、將得到的流對象轉換為集合。 Collect()即為收集器用來將經過篩選、映射的流進行最后的整理
groupingBy() 分組
/joining()連接流中每個元素的toString方法生成的字符串
/reducing()是針對單個值的收集,其返回結果不是集合家族的類型,而是單一的實體類T
/collectingAndThen()轉換函數返回的類型
/Counting()計算流中個數/
SummingInt()對流中元素的一個整數屬性求和
/averagingInt()計算流中元素integer屬性的平均值
maxBy()比較器選出的最大元素的optional,如果為空返回的是Optional.empty()
minBy()比較器選出的最小元素的optional,如果為空返回的是Optional.empty()
Collectors的常用封裝有:toList()/toMap()/toCollection()/toSet()
map() 映射
distinct()去重
limit(3)截取流的前N個元素
skip(3)跳過流的前n個元素
equels() 比較
anyMatch()判斷流中是否匹配任意元素
allMatch()判斷流中是否匹配任意元素
noneMatch()判斷流中是否未匹配所有元素
findAny()從流中獲取任意元素,返回一個Optional類型的元素
Optional是Java8新加入的一個容器,這個容器只存1個或0個元素,它用于防止出現NullpointException,它提供如下方法:
isPresent()
判斷容器中是否有值。
ifPresent(Consume lambda)
容器若不為空則執行括號中的Lambda表達式。
T get()
獲取容器中的元素,若容器為空則拋出NoSuchElement異常。
T orElse(T other)
獲取容器中的元素,若容器為空則返回括號中的默認值。
---------------------
reduce()歸約? 是將集合中的所有元素經過指定運算,折疊成一個元素輸出
? ? ? ? ? ?數值流采用reduce進行數值操作會涉及到基本數值類型和引用數值類型之間的裝箱、拆箱操作,因此效率較低。?
? ? ? ? ? ?當流操作為純數值操作時,使用數值流能獲得較高的效率。
? ? ? ? ? ?StreamAPI提供了三種數值流:IntStream、DoubleStream、LongStream,也提供了將普通流轉換成數值流的三種方法:mapToInt、mapToDouble、mapToLong。?
? ? ? ? ? ?每種數值流都提供了數值計算函數,如max、min、sum等
forEach()循環
sort()排序
sorted()排序
Comparator()排序
詳細使用參考:https://blog.csdn.net/u010425776/article/details/52344425
轉載于:https://www.cnblogs.com/Bkxk/p/11169833.html
總結
以上是生活随笔為你收集整理的Java8 lambda函数式编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ 术语(C++ Primer)
- 下一篇: mac php Swoole入门