目录
文章目录
Lambda表达式
Lambda表达式说白了就是简洁的表示匿名参数
举个栗子,在Collector的排序中我们可以自定义比较的方法,代码一般写成
## 比如说商品按照价格排序
Comparator<Goods> comp = new Comparator<Goods> () {
public int compare(Goods v1, Goods v2) {
return v1.getPrice() > v2.getPrice();
}
}
如果替换成jdk中的Lambda表达式的话,可以简化成为
(v1, v2) -> v1.getPrice() > v2.getPrice();
简化了比较类的声明以及各种繁琐的Override,代码看起来更加简洁
数据流操作
流是Java 8 API的一个新的接口,可以使用声明式的方法来处理数据集合,通俗点理解的话可以看做是一个迭代器。
和常见的流以及迭代器一样,Java 8的流都是一次性的。你在遍历到一半的时候,如果你想回退访问上一个数据,抱歉这个不可能,你只能重新开一个新的流或者自己想办法。
ps. 个人认为,在流操作中,最重要的是你要知道当前的流数据中是什么形式的内容。理解这点,在写代码和读代码优化上会更加快捷
后续都以商品类Goods作为举例,代码为伪代码,不一定能执行
public class Goods {
int price; // 价格,偷懒算他全部是整数吧
String name; // 商品名称
int category; // 商品类目
}
流中常用的函数说明
stream(打开数据流)
List<Goods> list = goodsDAO.getSomeGoods();
list.stream().doSomething();
通过stream()方法,可以得到一个商品类的流。
另外还有parallelStream()方法,也是一个获取流的方法,但是这个是一个并发流,可以充分使用多线程进行操作,不保障线程安全,具体看你的写法。
collect(数据收集)
List<Goods> newList = list.stream().doSomething().collect(Collectors.toList());
通过stream()方法得到的是一个流,如果想要得到一个数据还得将流中的数据收集起来
filter(过滤)
// 获取列表中价格大于100元的商品
list.stream().filter(v -> v.getPrice() > 100).collect(Collectors.toList());
distinct(去重)
limit(截断)
list.stream().limit(3).collect(toList())
获取列表的前三个元素
skip(跳过)
list.stream().filter(v -> v.getPrice() > 100).skip(3).collect(toList());
价格大于100,去掉头两个元素,剩余的数据列表
map(映射,常用之一)
通常情况下,我们有一个商品的列表,我们可能需要提取其中的商品价格或者商品名称,以完成一些操作,这时候需要做流中数据的映射
// 获取商品列表中名字带有“促销”字样的商品名字
List<String> onSaleNames = goodsList
.stream() // 此时数据流中对象为Goods对象
.map(Goods::getName) // 通过getName映射,此时流中的对象为商品名称
.filter(v -> v.contain("促销")) // 过滤,获取带有需要字样的名称
.collect(toList())
reduce(规约,常用之一,通常用来做统计)
// 多线程统计商品列表中所有商品的价格之和
int totalPrice = list.stream().map(Goods::getPrice).reduce(0, (l, r) -> l + r);
reduce(0, (l, r) -> l + r)是一个规约方法,0表示声明一个初始值,并且作为lambda表达式(l, r)中l的初始值,等价于
int totalPrice;
int l = 0;
for (Goods item : goods) {
int r = item.getPrice();
l = l + r;
}
totalPrice = l;
如果列表数量很多的时候,几千上万甚至更多,可以使用parallelStream来替代stream
sorted(排序)
和集合工具类中的sort是相似的,传入Comparator方法,然后根据比较方法进行排序
// 按照商品价格升序排列
list.stream().sorted((l, r) -> l.getPrice() - r.getPrice()).collect(toList());
其他偶尔可能用到的方法
- anyMatch(v -> expr(v)),流中是否有符合条件的对象
- findFirst(),获取流中第一个数据,通常跟在filter后使用
- findAny(),获取流中任意一个数据,通常跟在filter后使用,与findFirst()的区别在于,在并发流中,获取第一个数据的复杂度更高,findAny()有着更好的效率。
几个无聊的示例
- 求带有“折扣”字样商品的价格总和
int price = list.stream()
.filter(v -> v.getName().contain("折扣"))
.map(v::getPrice)
.reduce(0, (l, r) -> l + r);
- 比如双十一计算购物车商品列表中的折后价
// 这个是计算折后价的方法,里边一堆子判断逻辑
private void calSingleDogPrice(Goods good) {
SingleRule rule = getRule();
// 计算折后价
good.setPrice(rule.act(good));
}
// 写在同一个类下的时候,可以通过this::Method这种方式来对流中每个对象都调用了一次Method方法,传入Goods对象
list.stream().forEach(this::calSingleDogPrice);