在实际工作开发中,会经常用到stream流Api来进行数据处理,转换和筛选等。尤其是lambda表达式和流API结合可以写出更加干净的代码。
Lambda表达式 --> 函数式编程(函数编程思想)
标准格式:
(参数列表) -> {代码}
举个列子,可以利用lambda表达式来实现Runnable,用() -> {}代码块替代了整个匿名类,从而创建线程。
// Java 8之前:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Before Java8, too much code for too little to do");
}
}).start();
//lambda方式:
new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
这个例子向我们展示了Java 8 lambda表达式的语法。你可以使用lambda写出如下代码:
(params) -> expression
(params) -> statement
(params) -> { statements }
作用:简化集合、数组操作的API。结合了Lambda表达式。
Stream流的三类方法
获取Stream流(下面主要介绍)
创建一条流水线,并把数据放到流水线上准备进行操作
中间方法
流水线上的操作。一次操作完毕之后,还可以继续进行其他操作。
终结方法
一个Streami流只能有一个终结方法,是流水线上的最后一个操
public static void main(String args[]){
// 集合获取stream流
List<String> list = Lists.newArrayList();
Stream<String> s = list.stream();
// map集合获取流
Map<String,Integer> map = new HashMap<>();
// 获取键流
Stream<String> keyStream = map.keySet().stream();
// 值流
Stream<Integer> valueStream = map.values().stream();
// 获取键值对数据流
Stream<Map.Entry<String,Integer>> keyAndValueStream = map.entrySet().stream();
}
@Data
public static class OrderInfo implements Serializable {
//详情id
private Integer id;
//订单号
private String orderNo;
//商品id
private Integer goodsId;
//商品名称
private String name;
//商品单价
private BigDecimal price;
//商品数量
private BigDecimal num;
public OrderInfo(Integer id, String orderNo, Integer goodsId, String name, BigDecimal price, BigDecimal num) {
this.id = id;
this.orderNo = orderNo;
this.goodsId = goodsId;
this.name = name;
this.price = price;
this.num = num;
}
}
public static void main(String[] args){
List<OrderInfo> orderInfoList = Lists.newArrayList();
OrderInfo info = new OrderInfo(1,"N001", 1, "香蕉", new BigDecimal("2.3"), new BigDecimal(2));
orderInfoList.add(info);
info = new OrderInfo(2,"N001", 2, "苹果", new BigDecimal("4.3"), new BigDecimal("3.5"));
orderInfoList.add(info);
info = new OrderInfo(3,"N002", 3, "橘子", new BigDecimal("3.3"), new BigDecimal(4));
orderInfoList.add(info);
info = new OrderInfo(4,"N003", 1, "香蕉", new BigDecimal("2.3"), new BigDecimal("3.4"));
orderInfoList.add(info);
info = new OrderInfo(5,"N003", 3, "橘子", new BigDecimal("3.3"), new BigDecimal("3.5"));
orderInfoList.add(info);
}
// list对象类型转化为map(key是id,value为OrderInfo)
Map<Integer,OrderInfo> listToMap1 = orderInfoList.stream().collect(
Collectors.toMap(OrderInfo::getId,orderInfo -> orderInfo)
);
// list对象转化为map存在重复key的情况(保存重复key的第一条记录)
Map<Integer, OrderInfo> listToMap2 = orderInfoList.stream().collect(
Collectors.toMap(OrderInfo::getGoodsId,Function.identity(),(k1,k2)->k1)
);
// list对象转化为map(key是id,value为商品名称)
Map<Integer,String> listToMap3 = orderInfoList.stream().collect(
Collectors.toMap(OrderInfo::getId,OrderInfo::getName)
);
// list对象转化为map(key是orderNo,value为list,又一个按照orderNo聚合操作)
Map<String,List<OrderInfo>> listToMap4 = orderInfoList.stream().collect(
Collectors.groupingBy(OrderInfo::getOrderNo)
);
// list对象转化为map(key是orderNo,value为商品id的List列表)
Map<String,List<Integer>> listToMap5 = orderInfoList.stream().collect(
Collectors.groupingBy(OrderInfo::getOrderNo,Collectors.mapping(OrderInfo::getGoodsId,Collectors.toList()))
);
// list对象转化为map(key是orderNo,value为订单对应的总价格)
Map<String,Double> listToMap6 = orderInfoList.stream().collect(
Collectors.groupingBy(OrderInfo::getOrderNo,Collectors.summingDouble(
orderInfo -> orderInfo.getNum().multiply(orderInfo.getPrice()).doubleValue()
))
);
// 遍历转化的map
System.out.println(JSON.toJSONString(listToMap6));
listToMap6.forEach((key,value)->{
System.out.println(key+":"+value);
});
// list对象转化为list(获取商品的id,组成列表,不去重)
List<Integer> listToIdList = orderInfoList.stream().map(OrderInfo::getGoodsId)
.collect(Collectors.toList());
// list对象转化为list(获取商品的id,组成列表,去重复)
List<Integer> listToIdList1 = orderInfoList.stream().map(OrderInfo::getGoodsId)
.distinct().collect(Collectors.toList());
// 对list进行筛选,(单价大于4元的订单详情列表)
List<OrderInfo> listToFilterList = orderInfoList.stream().filter(
orderInfo -> orderInfo.getPrice().doubleValue()>4).collect(Collectors.toList());
// 对list筛选,获取单价大于3元且数量大于等于4的订单列表
List<OrderInfo> listToFilterList1 = orderInfoList.stream().filter(
orderInfo -> orderInfo.getPrice().doubleValue()>3 && orderInfo.getNum().doubleValue()>=4
).collect(Collectors.toList());
// 按照价格,对list进行排序(价格从大到小)
List<OrderInfo> listToSortList = orderInfoList.stream().sorted(
Comparator.comparing(OrderInfo::getPrice).reversed()
).collect(Collectors.toList());
//价格从小到大排序,数量从小到大排序
List<OrderInfo> listToSortList1 = orderInfoList.stream().sorted(
Comparator.comparing(OrderInfo::getPrice).thenComparing(OrderInfo::getNum)
).collect(Collectors.toList());
// 价格从小到大,数量从大到小
Comparator<OrderInfo> c1 = Comparator.comparing(OrderInfo::getPrice);
Comparator<OrderInfo> c2 = Comparator.comparing(OrderInfo::getNum).reversed();
List<OrderInfo> listToSortList2 = orderInfoList.stream().sorted(
c1.thenComparing(c2)
).collect(Collectors.toList());
map将集合类(例如列表)元素进行转换的。还有一个 reduce() 函数可以将所有值合并成一个。Map和Reduce操作是函数式编程的核心操作,因为其功能,reduce 又被称为折叠操作。另外,reduce 并不是一个新的操作,你有可能已经在使用它。SQL中类似 sum()、avg() 或者 count() 的聚集函数,实际上就是 reduce 操作,因为它们接收多个值并返回一个值。流API定义的 reduceh() 函数可以接受lambda表达式,并对所有值进行合并。IntStream这样的类有类似 average()、count()、sum() 的内建方法来做 reduce 操作,也有mapToLong()、mapToDouble() 方法来做转换。这并不会限制你,你可以用内建方法,也可以自己定义。在这个Java 8的Map Reduce示例里,我们首先对所有价格应用 12% 的VAT,然后用 reduce() 方法计算总和。
// 为每个订单加上12%的税
// 老方法:
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double total = 0;
for (Integer cost : costBeforeTax) {
double price = cost + .12*cost;
total = total + price;
}
System.out.println("Total : " + total);
// 新方法:
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get();
System.out.println("Total : " + bill);