Stream API的大致介绍


Stream API

Java8中两个最重大的改变,一个是Lambda表达式,另外一个就是Stream API

Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

Stream的执行过程分为三步

1、创建stream

2、操作stream(查找、筛选、过滤等等)

3、执行stream

stream的操作属于惰性求值,即所有的操作是在执行stream时一次性执行。

1 创建stream

创建流的方式有四种,这里直接把创建方式的注释写进代码里

public static void main(String[] args) {
    //创建Stream
    //1、通过Collection系列集合提供的stream()或parallelStream()
    List<String> list=new ArrayList<>();
    Stream<String> stream = list.stream();

    //2、通过Arrays中的静态方法stream()获取
    Integer[] integers=new Integer[10];
    Stream<Integer> stream1 = Arrays.stream(integers);

    //3、通过Stream类中的静态方法of()
    Stream<Integer> stream2 = Stream.of(integers);

    //4、迭代创建
    Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2);
}

2 操作stream

stream有多种操作集合的方法,下面一一进行讲解:

为了更方便的演示,新建一个实体类User:

public class User {
    private String name;
    private int age;
    private String sex;
    //这里省略构造方法、get、set、toString方法
}

filter过滤--通过某种条件过滤元素:

filter通过Predicate接口过滤元素,下面这段代码将年龄超过30岁的过滤出来

public static void main(String[] args) {
    List<User> list= Arrays.asList(
            new User("javayz",23,"male"),
            new User("张三",25,"male"),
            new User("李四",30,"female"),
            new User("王五",33,"female")
            new User("王五",33,"female")
    );
    //过滤出年龄大于30岁的人
    Stream<User> userStream = list.stream().filter((e) -> e.getAge() >= 30);
   userStream.forEach((e)-> System.out.println(e));
}

limit截断--使元素不超过给定的数量

//对取出来的数据只展示一条
Stream<User> userStream = list.stream()
        .filter((e) -> e.getAge() >= 30)
        .limit(1);
userStream.forEach((e)-> System.out.println(e));

skip--跳过集合中的前n个数

可以和limit联合使用取出指定的范围的数

Stream<User> userStream = list.stream().skip(2);

distinct--去重,通过元素的hashcode()和equals()去除重复元素

去重是根据hashcode()和equals()方法判断重复元素的,因此实体类了需要重写hashcode()和equals()方法

Stream<User> userStream = list.stream().distinct();

map--通过Function接口对stream中的每个数据处理后返回新的数据

比如我想把所有的英文改为大写,就可以这样

List<String> list1=Arrays.asList("aa","bb","cc");
Stream<String> stringStream = list1.stream().map((str) -> str.toUpperCase());
stringStream.forEach((e)-> System.out.println(e));

flatmap--通过Function接口把stream的每一个值都换成另外个stream,最后再把所有stream连接成一个stream

这个方法的使用可能会比较难懂,通过一个例子,把包含三个字符串的集合中的每个字符串都分成一个个字符提取出来。比如把一个集合{"aa","bb","cc"}变成{'a','a','b','b','c','c'},使用map就需要这样:

List<String> list1=Arrays.asList("aa","bb","cc");
Stream<Stream<Character>> streamStream = list1.stream().map((str) -> {
    List<Character> characters = new ArrayList<>();
    for (Character ch : str.toCharArray()) {
        characters.add(ch);
    }
    return characters.stream();
});
streamStream.forEach((stream)->{
    stream.forEach((character -> System.out.println(character)));
});

它第一个stream的返回值是stream中套一个字符流,输出的时候也需要先遍历最外层的stream再遍历内层的stream,比较麻烦,于是就可以使用flatmap,他会把多个stream合并为一个。

Stream<Character> characterStream = list1.stream().flatMap((str) -> {
    List<Character> characters = new ArrayList<>();
    for (Character ch : str.toCharArray()) {
        characters.add(ch);
    }
    return characters.stream();
});
characterStream.forEach((e)-> System.out.println(e));

sorted--自然排序,按照Comparable方式排序

Stream<String> stringStream = list.stream().sorted();

sorted(Comparator comparator)--定制排序,自己写一个Comparator 实现排序

List<User> list= Arrays.asList(
        new User("javayz",23,"male"),
        new User("张三",25,"male"),
        new User("李四",30,"female"),
        new User("王五",33,"female")
);

Stream<User> sorted = list.stream().sorted((e1, e2) -> {
    return e1.getAge() == e2.getAge() ? 0 : e1.getAge() > e2.getAge() ? 1 : -1;
});
sorted.forEach((e)-> System.out.println(e));

3 执行stream

如果只是操作stream,流的数据是不会变化的,接下来介绍执行stream的一系列方法

首先把接下来会用的数据创建进来:

List<User> list= Arrays.asList(
        new User("javayz",23,"male"),
        new User("张三",25,"male"),
        new User("李四",30,"female"),
        new User("王五",33,"female")
);

allMatch--检查是否匹配所有元素

//判断所有的元素的sex是否都是male,这里返回false
boolean male = list.stream().allMatch((e) -> e.getSex().equals("male"));
System.out.println(male);

anyMatch--检查是否至少匹配一个元素

boolean male = list.stream().anyMatch((e) -> e.getSex().equals("male"));
System.out.println(male);//这里返回true

noneMatch--检查是不是没有元素能够匹配指定的规则

boolean male = list.stream().noneMatch((e) -> e.getSex().equals("male"));
System.out.println(male);//这里返回false

findFirst--返回第一个元素

Optional<User> first = list.stream().findFirst();
System.out.println(first.get());

findAny--返回当前流中的任意一个元素

Optional<User> first = list.stream().findAny();
System.out.println(first.get());

count--返回当前流中的元素总个数

long count = list.stream().count();
System.out.println(count);

max--返回当前流中的最大值

返回最大值和最小值依旧需要实现comparator接口方法

Optional<User> max = list.stream().max((e1, e2) -> {
    return Integer.compare(e1.getAge(), e2.getAge());
});
System.out.println(max.get());

min--返回当前流中的最小值

Optional<User> max = list.stream().min((e1, e2) -> {
    return Integer.compare(e1.getAge(), e2.getAge());
});
System.out.println(max.get());

reduce--规约,将流中的元素反复结合起来,得到一个值

List<Integer> list=Arrays.asList(1,2,3,4,5,6,7,8,9);
//从第0个元素开始,对list求和
Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(reduce);

collection--收集,将流中的数据接收成其他的形式

比如,我们把上面User数据的名字收集到List数组中:

List<String> collect = list.stream().map((e) -> e.getName()).collect(Collectors.toList());
System.out.println(collect);

注意:

Collectors 提供了大量的转化为其他方式的实现,这里不做过多介绍。

JAVA-技能点
知识点