Java8 Stream(三):StreamAPI

初始数据

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]
上一篇:C# 批量操作对象属性


下一篇:toRef 和 toRefs