什么是Stream

PS:

  • Stream自己不会存储元素
  • Stream不会改变源对象,相反,他们会返回一个持有结果的新Stream
  • Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行

下面的图可以比较直观的反映这一过程:
Java8新特性 - Stream API-LMLPHP

  • 创建Stream
    一个数据源(数组、集合等),获取一个流
  • 中间操作
    一个中间操作链,对数据源的数据进行处理
  • 终止操作(终端操作)
    一个终止操作,执行中间操作链,并产生结果

创建Stream

通过Collection系列集合提供的stream()或parallelStream()

示例代码:

List<Integer> list = new ArrayList<>();
Stream<Integer> stream1 = list.stream();
Stream<Integer> stream2 = list.parallelStream();

由数组创建流

示例代码:

Integer[] integers = new Integer[10];
Stream<Integer> stream = Arrays.stream(integers);

由值创建流

示例代码:

Stream<Integer> stream = Stream.of(1, 2, 3);

创建无限流

示例代码:

// 迭代
Stream stream1 = Stream.iterate(0, (x) ->  x + 2);
// 生成
Stream stream2 = Stream.generate(() -> Math.random());

中间操作

筛选与切片

示例代码:

public class TestStreamApi {
    private static List<Demo> demoList = Arrays.asList(
            new Demo(1, "哈哈哈"),
            new Demo(2, "嘿嘿嘿嘿"),
            new Demo(3, "呵呵呵"),
            new Demo(4, "恩恩恩恩"),
            new Demo(5, "哼哼哼"),
            new Demo(6, "啧啧啧"),
            new Demo(5, "哼哼哼"),
            new Demo(8, "哼")
    );

    public static void main(String[] args) {
        // 中间操作不会执行任何操作
        Stream<Demo> demoStream = demoList.stream()
                .filter((x) -> x.getRemark().length() == 3)
                .limit(4)
                .skip(1)
                .distinct();

        // 终止操作一次性执行全部内容
        // 内部迭代:迭代操作由Stream API完成
        demoStream.forEach(System.out::println);
    }
}

运行结果:
3-呵呵呵
5-哼哼哼
6-啧啧啧

注意:distinct筛选通过流所生成的元素的hashCode()和equals()去除重复元素,所以需要重写Demo的hashCode()和equals()方法。

映射

示例代码:

public class TestStreamApi {
    private static List<Demo> demoList = Arrays.asList(
            new Demo(1, "哈哈哈"),
            new Demo(2, "嘿嘿嘿嘿")
    );

    public static void main(String[] args) {
        demoList.stream()
                .map(Demo::getRemark)
                .flatMap(TestStreamApi :: filterCharacter)
                .forEach(System.out::println);
    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }
}

运行结果:






排序

示例代码:

public class TestStreamApi {
    private static List<Demo> demoList = Arrays.asList(
            new Demo(5, "哈哈哈"),
            new Demo(2, "嘿嘿嘿嘿"),
            new Demo(3, "呵呵呵"),
            new Demo(2, "哼哼哼"),
            new Demo(5, "啧啧啧")
    );

    public static void main(String[] args) {
        List<String> list = Arrays.asList("aaa", "bbb", "ccc");
        list.stream()
                .sorted()
                .forEach(System.out::println);
        System.out.println("----------");
        demoList.stream()
                .sorted((x, y) -> {
                    if (x.getNum().equals(y.getNum())) {
                        return x.getRemark().compareTo(y.getRemark());
                    } else {
                        return x.getNum().compareTo(y.getNum());
                    }
                })
                .forEach(System.out::println);
    }
}

运行结果:
aaa
bbb
ccc
----------
2-哼哼哼
2-嘿嘿嘿嘿
3-呵呵呵
5-哈哈哈
5-啧啧啧

终止操作

查找与匹配

示例代码:

public class TestStreamApi2 {
        private static List<Demo> demoList = Arrays.asList(
            new Demo("张三", 18, 6666.66, Demo.Status.BUSY),
            new Demo("李四", 38, 3333.33, Demo.Status.FREE),
            new Demo("王五", 28, 5555.55, Demo.Status.FREE),
            new Demo("赵六", 48, 7777.77, Demo.Status.BUSY),
            new Demo("王二麻子", 58, 8888.88, Demo.Status.VOCATION)

    );

    public static void main(String[] args) {
        // 是不是所有的对象都处于BUSY状态
        System.out.println(demoList.stream()
                .allMatch((d) -> d.getStatus().equals(Demo.Status.BUSY)));
        // 是否有对象处于BUSY状态
        System.out.println(demoList.stream()
                .anyMatch((d) -> d.getStatus().equals(Demo.Status.BUSY)));
        // 是否没有对象处于BUSY状态
        System.out.println(demoList.stream()
                .noneMatch((d) -> d.getStatus().equals(Demo.Status.BUSY)));
        // 获取工资最高的
        Optional<Demo> optionalDemo1 = demoList.stream()
                .sorted((x, y) -> -Double.compare(x.getSalary(), y.getSalary()))
                .findFirst();
        System.out.println(optionalDemo1.get());
        // 获取随机一个空闲的
        Optional<Demo> optionalDemo2 = demoList.stream()
                .filter((e) -> e.getStatus().equals(Demo.Status.FREE))
                .findAny();
        System.out.println(optionalDemo2.get());
        // 总数
        System.out.println(demoList.stream().count());
        // 工资最高的
        Optional<Demo> optionalDemo3 = demoList.stream()
                .max((x, y) -> Double.compare(x.getSalary(), y.getSalary()));
        System.out.println(optionalDemo3.get());
        // 最小的工资
        Optional<Double> optionalDemo4 = demoList.stream()
                .map(Demo::getSalary)
                .max(Double::compare);
        System.out.println(optionalDemo4.get());
    }
}

class Demo{
    // 姓名
    String name;
    // 年龄
    Integer age;
    // 工资
    Double salary;
    // 状态
    Status status;

    public Demo() {}

    public Demo(String name, Integer age, Double salary, Status status) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.status = status;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Demo demo = (Demo) o;
        return name.equals(demo.name) &&
                age.equals(demo.age) &&
                salary.equals(demo.salary) &&
                status == demo.status;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, salary, status);
    }

    @Override
    public String toString() {
        return "Demo{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", status=" + status +
                '}';
    }

    public enum Status{
        FREE,
        BUSY,
        VOCATION
    }
}

运行结果:
false
true
false
Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}
Demo{name='李四', age=38, salary=3333.33, status=FREE}
5
Demo{name='王二麻子', age=58, salary=8888.88, status=VOCATION}
8888.88

归约

示例代码:

public class TestStreamApi3 {
    private static List<Demo> demoList = Arrays.asList(
            new Demo("张三", 18, 6666.66, Demo.Status.BUSY),
            new Demo("李四", 38, 3333.33, Demo.Status.FREE),
            new Demo("王五", 28, 5555.55, Demo.Status.FREE),
            new Demo("赵六", 48, 7777.77, Demo.Status.BUSY),
            new Demo("王二麻子", 58, 8888.88, Demo.Status.VOCATION)
    );

    public static void main(String[] args) {
        Optional<Double> optional = demoList.stream()
                .map(Demo::getSalary)
                .reduce(Double::sum);
        System.out.println(optional.get());
    }
}

运行结果:
32222.190000000002

收集

示例代码:

public class TestStreamApi4 {
    private static List<Demo> demoList = Arrays.asList(
            new Demo("张三", 18, 6666.66, Demo.Status.BUSY),
            new Demo("李四", 38, 3333.33, Demo.Status.FREE),
            new Demo("王五", 28, 5555.55, Demo.Status.FREE),
            new Demo("赵六", 48, 7777.77, Demo.Status.BUSY),
            new Demo("王二麻子", 58, 8888.88, Demo.Status.VOCATION)
    );

    public static void main(String[] args) {
        HashSet<String> set = demoList.stream()
                .map(Demo::getName)
                .collect(Collectors.toCollection(HashSet::new));
        set.forEach(System.out::println);
        // 总数
        System.out.println(demoList.stream()
                .collect(Collectors.counting()));

        // 工资平均值
        System.out.println(demoList.stream()
                .collect(Collectors.averagingDouble(Demo::getSalary)));
    }
}

运行结果:
李四
张三
王二麻子
王五
赵六
5
6444.438

10-27 06:45