stream() 是 JAVA8新增的一个强大特性,对于多种集合操作的支持可以极大减少代码量,不多说了,看场景
这有一个Apple的List,需要按照重量进行排序
public class Apple {
private String name;
private int weight;
private String color;
}
//--------------------------------------------------------
Apple apple1 = new Apple("a1", 80, "red");
Apple apple2 = new Apple("a2", 30, "green");
Apple apple3 = new Apple("a3", 30, "blue");
List<Apple> list = Arrays.asList(apple1, apple2, apple3);
这是List自带的方法实现按重量排序:
1: list.sort((a1,a2) -> a1.getWeight() - a2.getWeight());
2: list.sort(comparing((Apple a) -> a.getWeight()));
3: list.sort(comparing(Apple::getWeight));
倒序输出1: list.sort(comparing(Apple::getWeight).reversed());
是很方便,但是增加条件呢?
接下来,过滤
挑出重量大于150的苹果,别想着foreach了,直接上代码:
List<Aplle> heavyApple = list.stream().filter((Apple a) -> a.getWeight() > 150)
.collect(toList());
List<Aplle> heavyApple = list.parallelStream().filter((Apple a) -> a.getWeight() > 150)
.collect(toList());
其实lamda表达式很好理解,以这段为例:
List heavyApple = list.stream().filter((Apple a) -> a.getWeight() > 150)
.collect(toList());
从头开始看, .filter() 就是动词,正在做过滤操作,过滤条件是什么呢,
(Apple a) -> a.getWeight() > 150 , (Apple a) 是当前比较的实体对象,然后后面跟的是过滤的条件, a.getWeight() > 150,苹果重量大于150(想想是不是很像foreach),最后就是collect(toList()),意为生成一个新的List集合了,每步都透明的表达了自己的用义,阅读起来也很方便.
//-------------------------------------------------------------------------------------------------------
以上两种实现结果是一样的,需要说明一下,stream和parallelStream的区别,
parallelStream<<JAVA8实战>>书中解释大意为:…为了更好的利用日益强大的计算机CPU,实现并行处理… 需了解详情请百度.
好了,同理,如果需要找出绿色的苹果:
List<Apple> heavyApple = list.stream().filter(a -> a.getColor().equals("green")).collect(toList());
接着,颜色一样按颜色排序:
list1.sort(Comparator.comparing(Apple::getWeight).thenComparing(Apple::getColor));//没有返回值
前方高能,加量了!!!
需求:菜单选择400卡路里以下食物并排序,把菜肴名称保存在List里面
List<String> lowCaloricDishesName = menu.stream()
.filter(d -> d.getCalories() < 400) //小于400的实体
.sorted(comparing(Dish::getCalories)) //按卡路里(calories)排序
.map(Dish::getName) //只保存名字
.limit(3) //只选头三个
.collect(toList());
菜肴的实体参数不多,自己脑补啊
获取菜名长度
List<Integer> dishNamelength = menu.stream()
.map(Dish::getName)
.map(String::length)
.collect(toList());
查看是否所有菜品都符合健康(卡路里小于1000)
Boolean isHealthy = menu.stream()
.allMatch(d -> d.getCalories() < 1000);
allMatch,表示是否全部符合,如果条件符合return true,否则 fasle,这个场景也挺多的,数据库查的数据有时做二次过滤可以直接使用,noneMatch和这个作用差不多,标识是否全部不符合
查看是否所有菜品都不符合健康
Boolean isHealthy = menu.stream()
.noneMatch(d -> d.getCalories() >= 1000);
数值计算:
求和
List<Integer> stream = Arrays.asList(1, 1, 2, 2);
int sum = nums.stream().reduce(0,Integer :: sum);
//打印: 6
说明一下reduce第一个参数,第一个数我们给出的初始值,用于集合求和之后再对此值进行求和
int sum = nums.stream().reduce(6,Integer :: sum);
//打印: 12
最大值
int sum = nums.stream().reduce(Integer :: max);
最小值
int sum = nums.stream().reduce(Integer :: min);
再说一个筛选去重的方法,distinct
//一个存整数的数组
List<Integer> numList = Arrays.asList(2,5,5,5,6,3,1,7,4);
//获取大于四的所有数(不重复显示)
List<Integer> list5 = numList.stream().filter(a -> a > 4).distinct().collect(Collectors.toList());
//打印结果
System.out.println(list5.toString());
输出:[5, 6, 7]
//获取大于四的所有数(重复显示)
List<Integer> list5 = numList.stream().filter(a -> a > 4).collect(Collectors.toList());
输出:[5, 5, 5, 6, 7]
Map总结
Map<String, String> jsonMap = genJsonList.stream()
.collect(Collectors.toMap(RegexData::getGroupName, RegexData::getValue));
这行是我最近再做Json日志解析时候写的,需求是有两个list,需要对比其中的groupName,如果相等就获取对应的value.写两层List再for一下?虽然list数量不多,效率不会影响太大,但是很麻烦.所以,先把基准list(需要内部遍历的)里每个对象都转成Map<String,String>的键值对,然后只遍历一次外部list,比较的时候直接用基准list生成的map.get(groupName)就行了.当然了,生成Map的Value也可以为实体
Map<Integer, RegexData> regexMap = regexDataList.stream()
.collect(Collectors
.toMap(RegexData::getGroupIndex, RegexData -> RegexData));
只需要在RegexData 实体里加个构造方法就可以了,
注:此方法前提必须是Key为唯一的,Json日志解析出的key没有重复的,如果包含重复key值使用此方法会报错!
如果是使用key,value位为对象List呢,
Apple apple1 = new Apple("a1", 80, "red");
Apple apple2 = new Apple("a2", 30, "green");
Apple apple3 = new Apple("a3", 30, "blue");
Apple apple4 = new Apple("a3", 30, "blue");
Map<String, List<Apple>> map2 = list.stream()
.collect(Collectors.groupingByConcurrent(Apple::getColor));
打印结果:
{red=[NomarlizeTest.Lamda.Apple@2aae9190],
green=[NomarlizeTest.Lamda.Apple@2f333739],
blue=[NomarlizeTest.Lamda.Apple@77468bd9, NomarlizeTest.Lamda.Apple@12bb4df8]}
使用groupingByConcurrent,解析结果red和green都只有一个对象,blue有两个对象
//从list集合中,取出字段name的列表
List names = list.stream().map(p -> p.getName()).collect(Collectors.toList());
这里记录一些比较常用的,stream还有很多的处理方法,可以大大节省代码量