1. Stream流是什么?
JDK1.8 中增加了Stream流,Stream流是一种流式的处理数据的风格,也就是将要处理的数据当作流,在管道中进行传输,并在管道的每个节点对数据进行处理,如过滤、排序、转换等。
先来看一个Stream API的使用示例
List<String> sourceList = Arrays.asList("1", "2", "", "12", "5");
int sum = sourceList.stream()
.filter(StringUtils::isNotBlank)
.mapToInt(Integer::valueOf)
.sum();
System.out.println(sum);
这是个很简单的一个Stream使用例子,我们过滤掉空字符串后,转成int类型并对各个元素进行求和,这里有个三个操作:filter,mapToInt,sum。后面会详细介绍。
Stream内部通过流水线(Pipline)的方式来实现的,基本思路就是顺着流水线尽可能执行更多的操作,从而避免多次迭代。
Steam流操作有三个特性:
一个Stream流的使用主要包括三步:
、
Array等集合数据。生成Stream流的方式有三种,分别是
List<String> sourceList = Arrays.asList("1", "2", "", "12", "5");
//1.创建stream串行流对象
sourceList.stream();
//2.创建可并行执行的stream流对象
sourceList.parallelStream();
//3.通过给定的一系列元素创建一个新的Stream串行流对象
Stream.of("12", "123", "14", "15");
执行中间操作只是一种标记,只有结束操作才会触发实际计算。调用中间操作会返回一个新的流。 过滤,排序类的操作都是中间操作,中间操作可以有多个,中间操作分为无状态和有状态。
无状态:指元素的处理不受前面元素的影响。下面的方法均是无状态操作
方法 | 说明 |
---|---|
map() | 将已有元素转换为另一个对象类型,一对一逻辑 |
filter() | 按照条件过滤符号要求的元素 |
peek() | 对Stream流中的每个元素进行逐个遍历处理 |
unodered() | 返回一个无序的流,对于不关心顺序的数据处理和并行配合使用更佳。 |
mapToInt() | 将已有元素转成Int类型 |
mapToLong() | 将已有元素转成Long类型 |
mapToDouble() | 将已有元素转成Double类型 |
flatMap() | 将已有元素转换为另外对象类型,一对多逻辑 |
flatMapToInt() | 将已有元素转成Int类型 |
有状态:有状态的中间操作必须等所有元素处理之后才知道最终结果。比如排序是有状态的操作,在读取所有元素之前并不能确定排序结果。下面方法是有状态操作
方法 | 说明 |
---|---|
distinct() | 对stream中所有元素进行去重 |
sorted() | 结果排序 |
limit(n) | 仅保留集合前面指定个数的元素 |
skip(n) | 跳过集合前面指定个数的元素 |
concat() | 将两个流合并起来为1个新的流 |
终止操作就是指定stream流的输出结果。
方法 | 说明 |
---|---|
count() | 元素个数 |
max() | 最大值 |
min() | 最小值 |
findFirst() | 第一个符合条件 |
findAny() | 任意一个符合条件 |
anyMatch() | 判断是否有符合条件元素 |
allMatch() | 是否所有元素都符合条件 |
noneMatch() | 是否所有元素都不符合 |
collect(Collectors进行指定) | 将流转换成指定类型 |
toArray() | 转换成数组 |
iterator() | 转换成iterator()对象 |
foreach() | 逐个遍历 |
现在定义一个Apple类,此类有价格price,颜色color,重量weight,产地distinct 四个属性。
private static List<Apple> appleList = new ArrayList<>();
static {
appleList.add(new Apple(10, "red", 12, "安徽"));
appleList.add(new Apple(5, "red", 13, "江西"));
appleList.add(new Apple(5, "blue", 10, "江西"));
appleList.add(new Apple(40, "blue", 9, "河南"));
appleList.add(new Apple(15, "blue", 11, "浙江"));
}
}
public class Apple {
private Integer price;
private String color;
private Integer weight;
private String district;
public Apple(Integer price, String color, Integer weight, String district) {
this.price = price;
this.color = color;
this.weight = weight;
this.district = district;
}
省略getter和setter方法
}
//1.filter(过滤)筛选出所有颜色是红色的苹果
List<Apple> red = appleList.stream().filter(apple -> apple.getColor().equals("red")).collect(Collectors.toList());
//2.map的使用,将所有苹果重量+10,并且输出对应的苹果的产地
appleList.stream()
.map(apple -> {
apple.setWeight(apple.getWeight() + 10);
return apple;
}).map(Apple::getDistrict)
.collect(Collectors.toList());
//3.sorted() 排序
//按价格升序排序 自然排序
System.out.println("按价格升序排序 自然排序");
appleList.stream().sorted(Comparator.comparing(Apple::getPrice))
.peek(System.out::println).collect(Collectors.toList());
//按价格倒序排序 reversed()
System.out.println("按价格倒序排序 reversed()");
appleList.stream().sorted(Comparator.comparing(Apple::getPrice).reversed())
.peek(System.out::println).collect(Collectors.toList());
System.out.println("先按价格再按重量升序排序 thenComparing");
//先按价格再按重量升序排序 thenComparing
appleList.stream().sorted(Comparator.comparing(Apple::getPrice)
.thenComparing(Apple::getWeight))
.peek(System.out::println)
.collect(Collectors.toList());
//自定义排序,先按价格再按重量(降序)
System.out.println("自定义排序,先按价格再按年龄(降序)");
appleList.stream().sorted((p1, p2) -> {
if (p1.getPrice() == p2.getPrice()) {
return p2.getWeight() - p1.getWeight();
} else {
return p2.getPrice() - p1.getPrice();
}
}).peek(System.out::println).collect(Collectors.toList());
,将两个字符数组合并成一个新的字符数组
List<List<Integer>> lists = new ArrayList<>();
List<Integer> list = new ArrayList<>();
list.add(4444);
list.add(33333);
list.add(444444);
lists.add(list);
lists.stream().flatMap(Collection::stream).forEach(System.out::println);
List<String> strings = Arrays.asList("m,k,l,a", "1,3,4,5");
List<String> listNew = strings.stream().flatMap(s -> {
//将每个元素转成一个新的stream
String[] split = s.split(",");
Stream<String> s2 = Arrays.stream(split);
return s2;
}).collect(Collectors.toList());
System.out.println(listNew);
//创建两个流
Stream<String> stream1 = Stream.of("1", "2", "", "12", "5");
Stream<String> stream2 = Stream.of("3", "4", "5", "6");
//concat:合并两个流 //distinct:去重
List<String> lists1 = Stream.concat(stream1, stream2)
.distinct().collect(Collectors.toList());
//limit:限制从流中获取前n个数据
List<String> collect = stream1.limit(3).collect(Collectors.toList());
//skip:跳过前n个数据
List<String> collect1 = stream1.skip(2).collect(Collectors.toList());
//- 分区:将stream按条件分为两个Map,比如水果按照价格是否高于12分出两部分。
Map<Boolean,
List<Apple>> collect = appleList.stream().collect(Collectors.partitioningBy(apple -> apple.getPrice()
>
12));
//- 分组:将集合分为多个Map,比如水果按产地分组。有单级分组和多级分组。
Map<String,
List<Apple>> collect1 = appleList.stream().collect(Collectors.groupingBy(apple -> apple.getDistrict()));
//求平均重量
Double avg = appleList.stream().collect(Collectors.averagingDouble(Apple::getWeight));
//求和
Integer sum = appleList.stream().collect(Collectors.summingInt(Apple::getWeight));
//统计
List<Integer> orgNums =
Arrays.asList(3,
2,
2,
3,
7,
3,
5);
IntSummaryStatistics statistics = orgNums.stream().mapToInt((x)
-> x).summaryStatistics();
System.out.println("列表中最大的数:"
+ statistics.getMax());
System.out.println("列表中最小的数:"
+ statistics.getMin());
System.out.println("所有数之和:"
+ statistics.getSum());
System.out.println("平均数:"
+ statistics.getAverage());
//取出价格最高的苹果
appleList.stream().max(Comparator.comparing(Apple::getPrice)).get();
//取出价格最低的苹果
appleList.stream().min(Comparator.comparing(Apple::getPrice)).get();
//统计元素个数
appleList.stream().count();
//foreach
appleList.stream().filter(apple -> apple.getColor().equals("blue"))
.forEach(System.out::println);
//匹配第一个颜色是blue的苹果
appleList.stream().filter(apple -> apple.getColor().equals("blue"))
.findFirst();
//匹配任意一个颜色是blue的苹果
appleList.stream().filter(apple -> apple.getColor().equals("blue"))
.findAny();
//是否包含符合特定条件的元素
appleList.stream().anyMatch(apple -> apple.getColor().equals("blue"));
appleList.stream().map(Apple::getDistrict).collect(Collectors.toList());
//调用toMap方法时,如果key重复可以如下处理
Map<String,
Apple> collect = appleList.stream().collect(Collectors.toMap(Apple::getDistrict, a->a,(a1,a2)->a1));
//集合去重
Set<Apple> collect1 = appleList.stream().collect(Collectors.toSet());
List<String> list =
Arrays.asList("1","2","3","4");
//以空字符拼接,输出 1234
String result= list.stream().collect(Collectors.joining());
//以“-”符号拼接,输出1-2-3-4
String result1= list.stream().collect(Collectors.joining("-"));
System.out.println(result1);
多个参数
joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) 方法接受一个字符串序列作为拼接符,并在拼接完成后添加传递的前缀和后缀。假如我们传递的分隔符为 “-”,前缀为 “[” , 后缀为 “]” 。那么输出结果为 [1-2-3-4]
List<String> arrayList = Arrays.asList("1","2","3","4");
String collect = arrayList.stream().collect(Collectors.joining(",", "[", "]"));