java 8 lambda reduce_JDK8新特性Lambda表达式体验
“Lambda 表達(dá)式”(lambda expression)是一個(gè)匿名函數(shù),Lambda表達(dá)式基于數(shù)學(xué)中的λ演算得名,直接對(duì)應(yīng)于其中的lambda抽象(lambda abstraction),是一個(gè)匿名函數(shù),即沒(méi)有函數(shù)名的函數(shù)。Java 8的一個(gè)大亮點(diǎn)是引入Lambda表達(dá)式,使用它設(shè)計(jì)的代碼會(huì)更加簡(jiǎn)潔。當(dāng)開(kāi)發(fā)者在編寫(xiě)Lambda表達(dá)式時(shí),也會(huì)隨之被編譯成一個(gè)函數(shù)式接口。
Lambda簡(jiǎn)介
Lambda表達(dá)式的語(yǔ)法由參數(shù)列表、箭頭符號(hào)->和函數(shù)體組成。函數(shù)體既可以是一個(gè)表達(dá)式,也可以是一個(gè)語(yǔ)句塊。
比如:
(int x, int y) -> x + y;
具體的Lambda表達(dá)式的介紹可以看這篇博客,寫(xiě)得挺詳細(xì)的。
Java Lambda表達(dá)式示例
下面就用一些例子來(lái)體驗(yàn)一下Lambda表達(dá)式。
遍歷集合
比如我們現(xiàn)在要遍歷一個(gè)List:
List list = Arrays.asList("Hello", "JDK8", "and", "Lambda");
JDK8之前的寫(xiě)法:
for (String s : list) {
System.out.println(s);
}
用Lambda表達(dá)式寫(xiě)法:
list.forEach(s -> System.out.println(s));
可以看到,無(wú)論是代碼量和可讀性都得到了提高。
在此基礎(chǔ)上還可以再用隱式表達(dá)式進(jìn)行簡(jiǎn)化:
list.forEach(System.out::println);
匿名類(lèi)
在Java中很多時(shí)候我們要用到匿名類(lèi),比如線(xiàn)程Runnable、FileFilter和Comparator等等。
而匿名類(lèi)型最大的問(wèn)題就在于其冗余的語(yǔ)法。
這里用Comparator做例子。
比如我們有一個(gè)Cat類(lèi),表示貓,有名字、高度和重量這些屬性。
package com.fengyuan.model;
import lombok.AllArgsConstructor;
import lombok.Data;
public @Data @AllArgsConstructor class Cat {
private String name;
private double height;
private double weight;
}
我們創(chuàng)建3只貓,存到List中:
List catList = new ArrayList<>();
// 請(qǐng)無(wú)視這些數(shù)據(jù)的合理性,我亂寫(xiě)的
catList.add(new Cat("cat1", 10.3, 3.6));
catList.add(new Cat("cat2", 9.3, 4.6));
catList.add(new Cat("cat3", 9.5, 4.0));
然后我們現(xiàn)在要對(duì)這個(gè)List進(jìn)行排序,但是現(xiàn)在不知道是要怎么排,所以我們要定義一個(gè)比較器,指定用高度或者是重量來(lái)排序。
JDK8之前的寫(xiě)法:
// 指定用高度來(lái)排序
Collections.sort(catList, new Comparator() {
@Override
public int compare(Cat o1, Cat o2) {
if (o1.getHeight() > o2.getHeight()) {
return 1;
} else if (o1.getHeight() < o2.getHeight()) {
return -1;
} else {
return 0;
}
}
});
而用Lambda,可以這樣寫(xiě):
Collections.sort(catList, (o1, o2) -> {
if (o1.getHeight() > o2.getHeight()) {
return 1;
} else if (o1.getHeight() < o2.getHeight()) {
return -1;
} else {
return 0;
}
});
繼續(xù)用方法引用,可以簡(jiǎn)寫(xiě)到極致:
// 指定用重量排序
catList.sort(Comparator.comparing(Cat::getWeight));
// 要逆向排列也很簡(jiǎn)單
catList.sort(Comparator.comparing(Cat::getWeight).reversed());
到最后這種寫(xiě)法,已經(jīng)簡(jiǎn)寫(xiě)到極致,而且可讀性非常高。
函數(shù)式接口
JDK8增加了一個(gè)新的包:java.util.function,它里面包含了常用的函數(shù)式接口,比如Predicate、Consumer,Function等等。
接下來(lái)就體驗(yàn)一下Predicate和Consumer的用法。
我們現(xiàn)在有一個(gè)訂單類(lèi),有id,金額,運(yùn)費(fèi)這些屬性。這個(gè)訂單有一個(gè)折扣方法,我們希望能夠根據(jù)營(yíng)銷(xiāo)活動(dòng),動(dòng)態(tài)修改優(yōu)惠方案。
Order類(lèi):
package com.fengyuan.model;
import java.util.function.Consumer;
import java.util.function.Predicate;
import lombok.AllArgsConstructor;
import lombok.Data;
public @Data @AllArgsConstructor class Order {
private long id;
private double payment;
private double freight;
// 優(yōu)惠政策
public Order discount(Order order, Predicate predicate, Consumer consumer) {
// 滿(mǎn)足Predicate的條件,返回true
if (predicate.test(order)) {
// 接收訂單對(duì)象,對(duì)訂單對(duì)象進(jìn)行處理
consumer.accept(order);
}
return order;
}
}
其中
Predicate:接收T對(duì)象并返回boolean。
Consumer:接收T對(duì)象,沒(méi)有返回值。
然后通過(guò)函數(shù)式編程,我們可以動(dòng)態(tài)傳入我們的優(yōu)惠方案,比如99包郵:
// 新建一個(gè)訂單,506.5的金額,10.0的運(yùn)費(fèi)
Order order = new Order(123, 506.5, 10.0);
// 滿(mǎn)足金額>=99的條件,則設(shè)置運(yùn)費(fèi)為0
order.discount(order,
o -> o.getPayment() >= 99,
o -> o.setFreight(0));
這樣一來(lái),就能根據(jù)營(yíng)銷(xiāo)活動(dòng),修改我們的優(yōu)惠方案。
除此之外,Predicate對(duì)象之間還能運(yùn)用與或非這些邏輯操作,比如:
predicate1.and(predicate2);
predicate1.or(predicate2);
Stream
這里的Stream和I/O流不同,它更像具有Iterable的集合類(lèi)。
Stream API引入的目的在于彌補(bǔ)Java函數(shù)式編程的缺陷,讓java也支持map()、reduce()等函數(shù)式編程語(yǔ)言。
map
map(映射),將傳入的函數(shù)依次作用到序列的每個(gè)元素。
比如說(shuō),有一個(gè)字符串列表,我們現(xiàn)在給列表里每個(gè)字符串調(diào)用toLowerCase()方法,轉(zhuǎn)成小寫(xiě)字母。
List list = Arrays.asList("Hello", "JDK8", "and", "Lambda");
轉(zhuǎn)成小寫(xiě),用collect()把Stream再轉(zhuǎn)回List,返回新的列表:
List newList = list.stream().map(s -> s.toLowerCase()).collect(Collectors.toList());
也可以返回一個(gè)字符串,指定連接符,我這里是用空格連接的:
String str = list.stream().map(s -> s.toLowerCase()).collect(Collectors.joining(" "));
也可以用隱式函數(shù),String::toLowerCase來(lái)實(shí)現(xiàn):
String str = list.stream().map(String::toLowerCase).collect(Collectors.joining(" "));
reduce
reduce(歸約),將集合中所有值結(jié)合起來(lái)。
將一個(gè)整型List,先進(jìn)行map:每個(gè)數(shù)都翻一倍,再進(jìn)行reduce:所有數(shù)加起來(lái),得到結(jié)果:
List numbers = Arrays.asList(10, 20, 30, 40, 50);
int result = numbers.stream().map(num -> num * 2).reduce((r, num) -> r += num).get();
變量捕捉
一個(gè)簡(jiǎn)單的例子,算出一個(gè)集合中最大值、最小值、平均值等等。
集合:
List numbers = Arrays.asList(4, 6, 65, 3, 44, 2, 17, 19);
計(jì)算:
int max = numbers.stream().mapToInt(x -> x).max().getAsInt();
int min = numbers.stream().mapToInt(x -> x).min().getAsInt();
long count = numbers.stream().mapToInt(x -> x).count();
double avg = numbers.stream().mapToInt(x -> x).average().getAsDouble();
int sum = numbers.stream().mapToInt(x -> x).sum();
也可以用IntSummaryStatistics類(lèi)來(lái)得到統(tǒng)計(jì)結(jié)果:
IntSummaryStatistics stat = numbers.stream().mapToInt(x -> x).summaryStatistics();
int max = stat.getMax();
int min = stat.getMin();
long count = stat.getCount();
double avg = stat.getAverage();
long sum = stat.getSum();
結(jié)語(yǔ)
雖然平時(shí)項(xiàng)目的開(kāi)發(fā)中還是比較少用到Lambda表達(dá)式,但是在以上這些體驗(yàn)中,確實(shí)是感受到了它的魅力。
總結(jié)
以上是生活随笔為你收集整理的java 8 lambda reduce_JDK8新特性Lambda表达式体验的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 习惯性流产对患者的危害
- 下一篇: 吴京的新片(攀登者)大家听过没有?