初始数据
Animal类
public class Animal{
private String name;
private String type;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Animal() {
}
public Animal(String name, String type, Integer age) {
this.name = name;
this.type = type;
this.age = age;
}
@Override
public String toString() {
return "{name='" + name + '\'' +
", type='" + type + '\'' +
", age=" + age + "}";
}
}
初始数据
//初始Integer数组
List<Integer> list = Arrays.asList(4, 3, 7, 9, 8, 2, 1);
//初始Animal数组
List<Animal> animalList = new ArrayList<>();
animalList.add(new Animal("皮皮", "狗", 5));
animalList.add(new Animal("犇犇", "狗", 1));
animalList.add(new Animal("小六", "狗", 2));
animalList.add(new Animal("咪咪", "猫", 3));
animalList.add(new Animal("胖虎", "猫", 10));
animalList.add(new Animal("来福", "猫", 2));
1 遍历/查找/匹配 foreach/find/match
1.1. forEach 遍历元素
//foreach 遍历输出元素
//遍历初始Integer数组
System.out.println("遍历初始Integer数组:");
list.stream().forEach(System.out::println);
//遍历初始Animal数组数组
System.out.println("遍历初始Animal数组:");
animalList.stream().forEach(System.out::println);
输出结果:
遍历初始Integer数组:
4
3
7
9
8
2
1
遍历初始Animal数组:
{name='皮皮', type='狗', age=5}
{name='犇犇', type='狗', age=1}
{name='小六', type='狗', age=2}
{name='咪咪', type='猫', age=3}
{name='胖虎', type='猫', age=10}
{name='来福', type='猫', age=2}
1.2. find 查找
//find 查找
//findFirst 查找初始Integer数组中的第一个
Optional<Integer> findFirstInteger = list.stream().findFirst();
//findFirst 查找初始Integer数组中的第一个
Optional<Animal> findFirstAnimal = animalList.stream().findFirst();
System.out.println("查找初始Integer数组中的第一个:" + findFirstInteger.get());
System.out.println("查找初始Integer数组中的第一个:" + findFirstAnimal.get());
//findAny 查找初始Integer数组中的任意一个(适用于并行流)
Optional<Integer> findAnyInteger = list.parallelStream().findAny();
//findAny 查找初始Animal数组中的任意一个(适用于并行流)
Optional<Animal> findAnyAnimal = animalList.parallelStream().findAny();
System.out.println("查找初始Integer数组中的任意一个(适用于并行流):" + findAnyInteger.get());
System.out.println("查找初始Animal数组中的任意一个(适用于并行流):" + findAnyAnimal.get());
输出结果:
查找初始Integer数组中的第一个:4
查找初始Integer数组中的第一个:{name='皮皮', type='狗', age=5}
查找初始Integer数组中的任意一个(适用于并行流):8
查找初始Animal数组中的任意一个(适用于并行流):{name='皮皮', type='狗', age=5}
1.3. match 匹配
//match 匹配
//anyMatch 初始Integer数组任意一个满足条件 数值大于6
boolean anyMatchInteger = list.stream().anyMatch(x -> x > 6);
//anyMatch 初始Animal数组任意一个满足条件 年龄大于2
boolean anyMatchAnimal = animalList.stream().anyMatch(x -> x.getAge() > 2);
System.out.println("初始Integer数组任意一个满足条件 数值大于6:" + anyMatchInteger);
System.out.println("初始Animal数组任意一个满足条件 年龄大于2:" + anyMatchAnimal);
//allMatch 初始Integer数组全部满足条件 数值大于6
boolean allMatchInteger = list.stream().allMatch(x -> x > 6);
//anyMatch 初始Animal数组全部满足条件 年龄大于2
boolean allMatchAnimal = animalList.stream().allMatch(x -> x.getAge() > 2);
System.out.println("初始Integer数组全部满足条件 数值大于6:" + allMatchInteger);
System.out.println("初始Animal数组全部满足条件 年龄大于2:" + allMatchAnimal);
输出结果:
初始Integer数组任意一个满足条件 数值大于6:true
初始Animal数组任意一个满足条件 年龄大于2:true
初始Integer数组全部满足条件 数值大于6:false
初始Animal数组全部满足条件 年龄大于2:false
2 筛选 filter
//filter 初始Integer数组中全部满足条件 数值大于6
List<Integer> newListInteger = list.stream()
.filter(x -> x > 6)
.collect(Collectors.toList());
//filter 初始Animal数组中全部满足条件 年龄大于2
List<Animal> newListAnimal = animalList.stream()
.filter(x -> x.getAge() > 2)
.collect(Collectors.toList());
System.out.println("初始Integer数组中全部满足条件 数值大于6:");
newListInteger.forEach(System.out::println);
System.out.println("初始Animal数组中全部满足条件 年龄大于2:");
newListAnimal.forEach(System.out::println);
输出结果:
初始Integer数组中全部满足条件 数值大于6:
7
9
8
初始Animal数组中全部满足条件 年龄大于2:
{name='皮皮', type='狗', age=5}
{name='咪咪', type='猫', age=3}
{name='胖虎', type='猫', age=10}
3 聚合 max/min/count
3.1 max 获取最大元素 min 获取最小元素
//max
//max 对初始Integer数组 自然排序 获取最大元素
Optional<Integer> maxInteger1 = list.stream().max(Integer::compareTo);
//max 对初始Animal数组 自然排序 获取最大元素
//需要Animal 实现Comparable接口
Optional<Animal> maxAnimal1 = animalList.stream().max(Animal::compareTo);
System.out.println("对初始Integer数组 自然排序 获取最大元素:" + maxInteger1.get());
System.out.println("对初始Animal数组 自然排序 获取最大元素:" + maxAnimal1.get());
//max 对初始Integer数组 自定义排序 排除数值9 获取最大元素
Optional<Integer> maxInteger2 = list.stream().max((o1, o2) -> {
if (o1 == 9) {
return -1;
}
return o1.compareTo(o2);
});
//max 对初始Animal数组 自定义排序 获取最大元素
Optional<Animal> maxAnimal2 = animalList.stream().max((o1, o2) -> {
return o1.getAge() - o2.getAge();
});
Optional<Animal> maxAnimal3 = animalList.stream().max(Comparator.comparingInt(Animal::getAge));
System.out.println("对初始Integer数组 自定义排序 排除数值9 获取最大元素:" + maxInteger2.get());
System.out.println("对初始Animal数组 自定义排序 获取最大元素:" + maxAnimal2.get());
System.out.println("对初始Animal数组 自定义排序 获取最大元素:" + maxAnimal3.get());
Animal类修改
public class Animal implements Comparable {
...省略
...省略
@Override
public int compareTo(Object o) {
Animal animal = (Animal) o;
return this.getAge() - animal.getAge();
}
}
输出结果:
对初始Integer数组 自然排序 获取最大元素:9
对初始Animal数组 自然排序 获取最大元素:{name='胖虎', type='猫', age=10}
对初始Integer数组 自定义排序 排除数值9 获取最大元素:8
对初始Animal数组 自定义排序 获取最大元素:{name='胖虎', type='猫', age=10}
对初始Animal数组 自定义排序 获取最大元素:{name='胖虎', type='猫', age=10}
3.2 count 获取元素数量
//count 初始Integer数组 数值大于6元素数量
long countInteger = list.stream()
.filter(x -> x > 6)
.count();
//count 初始Animal数组 年龄大于2元素数量
long countAnimal = animalList.stream()
.filter(x -> x.getAge() > 2)
.count();
System.out.println("初始Integer数组 数值大于6元素数量:" + countInteger);
System.out.println("初始Animal数组 年龄大于2元素数量:" + countAnimal);
结果输出:
初始Integer数组 数值大于6元素数量:3
初始Animal数组 年龄大于2元素数量:3
4 map 映射
4.1 map 一对一映射
//map 一对一映射 初始Integer数组每个元素+10
List<Integer> mapListInteger = list.stream()
.map(x -> x + 10)
.collect(Collectors.toList());
System.out.println("一对一映射 初始Integer数组每个元素+10:");
mapListInteger.forEach(System.out::println);
//map 一对一映射 初始Animal数组每个名称拼接~~~
List<Animal> mapListAnimal = animalList.stream()
.map(x -> {
x.setName(x.getName() + "~~~");
return x;
})
.collect(Collectors.toList());
System.out.println("一对一映射 初始Animal数组每个名称拼接~~~:");
mapListAnimal.forEach(System.out::println);
结果输出:
一对一映射 初始Integer数组每个元素+10:
14
13
17
19
18
12
11
一对一映射 初始Animal数组每个名称拼接~~~:
{name='皮皮~~~', type='狗', age=5}
{name='犇犇~~~', type='狗', age=1}
{name='小六~~~', type='狗', age=2}
{name='咪咪~~~', type='猫', age=3}
{name='胖虎~~~', type='猫', age=10}
{name='来福~~~', type='猫', age=2}
4.2 flatMap 1对多映射
//flatMapListInteger 一对多映射 初始Integer数组 一个+10,一个-10:
List<Integer> flatMapListInteger = list.stream().flatMap(x -> {
List<Integer> integers = new ArrayList<>();
integers.add(x + 10);
integers.add(x - 10);
return integers.stream();
}).collect(Collectors.toList());
System.out.println("一对多映射 初始Integer数组 一个+10,一个-10:");
flatMapListInteger.forEach(System.out::println);
//flatMapListAnimal 一对多映射 初始Animal数组 名称一个拼接~~~,一个拼接!!!
//需要Animal 实现Cloneable接口
List<Animal> flatMapListAnimal = animalList.stream().flatMap(x -> {
List<Animal> animals = new ArrayList<>();
Animal clone = x.clone();
x.setName(x.getName() + "~~~");
clone.setName(clone.getName() + "!!!");
animals.add(x);
animals.add(clone);
return animals.stream();
}).collect(Collectors.toList());
System.out.println("一对多映射 初始Animal数组 名称一个拼接~~~,一个拼接!!!");
flatMapListAnimal.forEach(System.out::println);
Animal类修改
@Override
public Animal clone() {
Animal animal = null;
try {
animal = (Animal) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return animal;
}
输出结果:
一对多映射 初始Integer数组 一个+10,一个-10:
14
-6
13
-7
17
-3
19
-1
18
-2
12
-8
11
-9
一对多映射 初始Animal数组 名称一个拼接~~~,一个拼接!!!
{name='皮皮~~~~~~', type='狗', age=5}
{name='皮皮~~~!!!', type='狗', age=5}
{name='犇犇~~~~~~', type='狗', age=1}
{name='犇犇~~~!!!', type='狗', age=1}
{name='小六~~~~~~', type='狗', age=2}
{name='小六~~~!!!', type='狗', age=2}
{name='咪咪~~~~~~', type='猫', age=3}
{name='咪咪~~~!!!', type='猫', age=3}
{name='胖虎~~~~~~', type='猫', age=10}
{name='胖虎~~~!!!', type='猫', age=10}
{name='来福~~~~~~', type='猫', age=2}
{name='来福~~~!!!', type='猫', age=2}
5 归约 reduce
//reduce 求和方式1
Optional<Integer> sum1 = list.stream().reduce((x, y) -> x + y);
//reduce 求和方式2
Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
//reduce 求和方式3
Integer sum3 = list.stream().reduce(0, Integer::sum);
System.out.println("reduce 求和方式1:" + sum1.get());
System.out.println("reduce 求和方式2:" + sum2.get());
System.out.println("reduce 求和方式3:" + sum3);
输出结果:
reduce 求和方式1:34
reduce 求和方式2:34
reduce 求和方式3:34
6 收集 collect
6.1 归集 toList/toSet/toMap
//collect 归集 toList/toSet/toMap
List<Integer> collectList = list.stream()
.filter(item -> item < 8)
.collect(Collectors.toList());
Set<Integer> collectSet = list.stream()
.filter(item -> item < 8)
.collect(Collectors.toSet());
Map<Integer, Integer> collectMap = list.stream()
.filter(item -> item < 8)
.collect(Collectors.toMap(item -> item, item -> item));
System.out.println("collect 归集toList:" + collectList);
System.out.println("collect 归集toSet:" + collectSet);
System.out.println("collect 归集toMap:" + collectMap);
输出结果:
collect 归集toList:[4, 3, 7, 2, 1]
collect 归集toSet:[1, 2, 3, 4, 7]
collect 归集toMap:{1=1, 2=2, 3=3, 4=4, 7=7}
注:如果map中有重复的key,会报错
Exception in thread "main" java.lang.IllegalStateException: Duplicate key 1
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1254)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.zhow.Stream_04_Test.main(Stream_04_Test.java:33)
6.2 统计 count/averaging
// 求总数
Long count = list.stream().collect(Collectors.counting());
// 求平均
Double average = list.stream().collect(Collectors.averagingDouble(Integer::doubleValue));
// 求最高
Optional<Integer> max = list.stream().collect(Collectors.maxBy(Integer::compare));
// 求和
Integer sum = list.stream().collect(Collectors.summingInt(Integer::intValue));
// 一次性统计所有信息
DoubleSummaryStatistics collect = list.stream().collect(Collectors.summarizingDouble(Integer::intValue));
System.out.println("总数:" + count);
System.out.println("平均:" + average);
System.out.println("最高:" + max);
System.out.println("总和:" + sum);
System.out.println("所有统计:" + collect);
输出结果:
总数:7
平均:4.857142857142857
最高:Optional[9]
总和:34
所有统计:DoubleSummaryStatistics{count=7, sum=34.000000, min=1.000000, average=4.857143, max=9.000000}
6.3 分组 partitioningBy/groupingBy
//分组 partitioningBy/groupingBy
// 按动物年龄大于4分组
Map<Boolean, List<Animal>> age = animalList.stream().collect(Collectors.partitioningBy(x -> x.getAge() > 4));
// 按动物类别分组
Map<String, List<Animal>> type = animalList.stream().collect(Collectors.groupingBy(Animal::getType));
// 将员工先按性别分组,再按地区分组
Map<String, Map<Boolean, List<Animal>>> ageType = animalList.stream().collect(Collectors.groupingBy(Animal::getType, Collectors.groupingBy(x -> x.getAge() > 4)));
System.out.println("按动物年龄大于4分组:" + age);
System.out.println("按动物类别分组:" + type);
System.out.println("按动物按类别、年龄:" + ageType);
结果输出:
按动物年龄大于4分组:{false=[{name='犇犇', type='狗', age=1}, {name='小六', type='狗', age=2}, {name='咪咪', type='猫', age=3}, {name='来福', type='猫', age=2}], true=[{name='皮皮', type='狗', age=5}, {name='胖虎', type='猫', age=10}]}
按动物类别分组:{狗=[{name='皮皮', type='狗', age=5}, {name='犇犇', type='狗', age=1}, {name='小六', type='狗', age=2}], 猫=[{name='咪咪', type='猫', age=3}, {name='胖虎', type='猫', age=10}, {name='来福', type='猫', age=2}]}
按动物按类别、年龄:{狗={false=[{name='犇犇', type='狗', age=1}, {name='小六', type='狗', age=2}], true=[{name='皮皮', type='狗', age=5}]}, 猫={false=[{name='咪咪', type='猫', age=3}, {name='来福', type='猫', age=2}], true=[{name='胖虎', type='猫', age=10}]}}
6.4 拼接 joining
//拼接 joining
//所有宠物名称拼接
String nameString = animalList.stream().map(Animal::getName).collect(Collectors.joining(","));
System.out.println("所有宠物名称拼接:" + nameString);
结果输出:
所有宠物名称拼接:皮皮,犇犇,小六,咪咪,胖虎,来福
6.5 归约 reducing
//归约 reducing
//宠物年龄总和
Optional<Integer> age2 = animalList.stream().map(Animal::getAge).collect(Collectors.reducing(Integer::sum));
System.out.println("宠物年龄总和:" + age2.get());
结果输出:
宠物年龄总和:23
7 排序 sorted
//7、排序
//自然排序 流中元素需实现Comparable接口
Stream<Animal> sorted1 = animalList.stream().sorted();
//按名字排序
Stream<Animal> sorted2 = animalList.stream().sorted(Comparator.comparing(Animal::getName));
//先按年龄再按名字排序
Stream<Animal> sorted3 = animalList.stream().sorted(Comparator.comparing(Animal::getAge).thenComparing(Animal::getName));
//自定义 先按年龄再按名字排序
Stream<Animal> sorted4 = animalList.stream().sorted((x, y) -> {
if (x.getAge() == y.getAge()) {
return x.getName().compareTo(y.getName());
} else {
return x.getAge() - y.getAge();
}
});
System.out.println("自然排序:");
sorted1.forEach(System.out::print);
System.out.println();
System.out.println("按名字排序:");
sorted2.forEach(System.out::print);
System.out.println();
System.out.println("先按年龄再按名字排序:");
sorted3.forEach(System.out::print);
System.out.println();
System.out.println("自定义 先按年龄再按名字排序:");
sorted4.forEach(System.out::print);
System.out.println();
结果输出:
自然排序:
{name='犇犇', type='狗', age=1}{name='小六', type='狗', age=2}{name='来福', type='猫', age=2}{name='咪咪', type='猫', age=3}{name='皮皮', type='狗', age=5}{name='胖虎', type='猫', age=10}
按名字排序:
{name='咪咪', type='猫', age=3}{name='小六', type='狗', age=2}{name='来福', type='猫', age=2}{name='犇犇', type='狗', age=1}{name='皮皮', type='狗', age=5}{name='胖虎', type='猫', age=10}
先按年龄再按名字排序:
{name='犇犇', type='狗', age=1}{name='小六', type='狗', age=2}{name='来福', type='猫', age=2}{name='咪咪', type='猫', age=3}{name='皮皮', type='狗', age=5}{name='胖虎', type='猫', age=10}
自定义 先按年龄再按名字排序:
{name='犇犇', type='狗', age=1}{name='小六', type='狗', age=2}{name='来福', type='猫', age=2}{name='咪咪', type='猫', age=3}{name='皮皮', type='狗', age=5}{name='胖虎', type='猫', age=10}
8 提取/组合
//提取/组合
//concat:合并两个流
Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4);
Stream<Integer> integerStream2 = Stream.of(5, 6, 7, 8);
List<Integer> concatList = Stream.concat(integerStream1, integerStream2).collect(Collectors.toList());
System.out.println("concat:合并两个流:" + concatList);
//distinct:去重
list = Arrays.asList(4, 3, 7, 9, 8, 2, 1, 3, 4);
List<Integer> distinctList = list.stream().distinct().collect(Collectors.toList());
System.out.println("去重:" + distinctList);
//limit:限制从流中获得前n个数据
List<Integer> limitList = list.stream().limit(5).collect(Collectors.toList());
System.out.println("限制从流中获得前5个数据:" + limitList);
//skip:跳过前n个数据
List<Integer> skipList = list.stream().skip(5).collect(Collectors.toList());
System.out.println("跳过前5个数据:" + skipList);
结果输出:
concat:合并两个流:[1, 2, 3, 4, 5, 6, 7, 8]
去重:[4, 3, 7, 9, 8, 2, 1]
限制从流中获得前5个数据:[4, 3, 7, 9, 8]
跳过前5个数据:[2, 1, 3, 4]