Stream Api

1.什么是Stream

Stream Api对集合数据进行操作,就类似于使用sql执行的数据库查询

Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列.
集合讲的是数据,Stream讲的是计算

注意:

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

1.1 Stream的操作三步骤

  • 1.创建Stream
    一个数据源(如:集合、数组),获取一个流
  • 2.中间操作
    一个中间操作链,对数据源的数据进行处理
  • 3.终止操作
    一旦执行了终止操作,就执行中间操作链,并产生结果,之后,不会再被使用

2.Stream实例化

2.1 通过集合

  • Stream<E> stream(): 返回一个顺序流
  • Stream<E> parallelStream(): 返回一个并行流
public void test() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小张", 32));
    list.add(new Person("小王", 12));

    // default Stream<E> Stream() 返回一个顺序流
    Stream<Person> stream = list.stream();

    // default Stream<E> parallelStream() 返回一个并行流
    Stream<Person> parallelStream = list.parallelStream();
}

2.2 通过数组

@Test
public void test2() {
    int[] arr = {1, 2, 3, 4, 5, 6};
    // 调用Arrays类的Stream<T> stream(T[] array) 返回一个流
    IntStream stream = Arrays.stream(arr);

    Person p1 = new Person("小张", 32);
    Person p2 = new Person("小王", 12);
    Person[] personArr = new Person[]{p1, p2};
    Stream<Person> stream1 = Arrays.stream(personArr);
}

2.3 通过Stream类的静态方法

@Test
public void test3() {
    Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
    Stream<Long> longStream = Stream.of(1L, 2L, 3L, 4L, 5L);
    Stream<Double> doubleStream = Stream.of(1.0, 2.0, 3.0, 4.0, 5.0);
    Stream<String> stringStream = Stream.of("1", "2", "3", "4", "5");
    Stream<Person> personStream = Stream.of(new Person("小张", 32), new Person("小王", 12));
}

2.4 创建无限流

  • Stream<T> iterate(final T seed, final UnaryOperator<T> f)
    final T seed:初始值
    final UnaryOperator<T> f:函数式接口,参数和返回值都是一个类型的
// 遍历从0开始的前10个偶数
 @Test
 public void test4() {
     Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
 }
  • Stream<T> generate(Supplier<T> s)
    Supplier<T> s:无参数,返回类型为任意类型的函数式接口
// 生成
Stream.generate(Math::random).limit(10).forEach(System.out::println);

3.Stream的中间操作

多个中间操作可以连接形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何处理!而在终止操作时,一次性全部处理,称为"惰性求值"

3.1 筛选和切片

  • filter(Predicate p)
    接收lambda,从流中排除某些元素
  • distinct()
    筛选,通过流所生成的元素 hashCode()和equals去除重复元素
  • limit(long maxSize)
    截断流,使其元素不超过给定数量
  • skip(long n)
    跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
@Test
public void test4() {
    getStream().filter(t -> t.age >20).forEach(System.out::println);
    getStream().limit(3).forEach(System.out::println);
    getStream().skip(2).forEach(System.out::println);
    // 需要重写Person类的hashCode()和equals()方法
    getStream().distinct().forEach(System.out::println);
}

public static Stream<Person> getStream() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小张", 32));
    list.add(new Person("小王", 12));
    list.add(new Person("小李", 16));
    return list.stream();
}

3.2 映射

  • map(Function<? super T, ? extends R> mapper)
    接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射为一个新的元素
  • <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
    接收一个函数作为参数,将流中每个值转换成另一个流,然后将所有流连成一个流
@Test
public void test5() {
    List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
    // 获取年龄大于20岁的人的姓名
    getStream().filter(t -> t.age > 20).map(t -> t.name).forEach(System.out::println);

    // 使用map
    Stream<Stream<Character>> streamStream = list.stream().map(StreamApi::fromStringToStream);
    streamStream.forEach(t -> {
        t.forEach(System.out::println);
        System.out.println("---");
    });

    // 使用flatMap
    Stream<Character> characterStream = list.stream().flatMap(StreamApi::fromStringToStream);
    characterStream.forEach(System.out::println);
}

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

public static Stream<Person> getStream() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小张", 32));
    list.add(new Person("小王", 12));
    list.add(new Person("小李", 16));
    return list.stream();
}

3.3 排序

@Test
public void test6() {
    List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98);
    // 自然排序
    list.stream().sorted().forEach(System.out::println);
    // 使用定制排序
    getStream().sorted((o1, o2) -> o2.age - o1.age).forEach(System.out::println);
}

public static Stream<Person> getStream() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小张", 32));
    list.add(new Person("小王", 12));
    list.add(new Person("小李", 16));
    return list.stream();
}

4.Stream的终止操作

4.1 匹配和查找

  • boolean allMatch(Predicate<? super T> predicate): 检查是否匹配所有元素
  • boolean anyMatch(Predicate<? super T> predicate): 检查是否至少匹配一个元素
  • boolean noneMatch(Predicate<? super T> predicate): 检查是否没有匹配的元素
  • Optional<T> findFirst(): 返回第一个元素
  • Optional<T> findAny(): 返回当前流中任意元素(在parallelStream下使用)
  • long count(): 返回流中元素的总个数
  • Optional<T> max(Comparator<? super T> comparator): 返回流中最大值
  • Optional<T> min(Comparator<? super T> comparator): 返回流中最小值
  • void forEach(Consumer<? super T> action): 内部迭代
@Test
public void test6() {
    // 是否所有人的年龄都大于18岁
    boolean b1 = getStream().allMatch(t -> t.age > 18);
    System.out.println(b1);

    // 是否存在大于18岁的人
    boolean b2 = getStream().anyMatch(t -> t.age > 18);
    System.out.println(b2);

    // 是否所有人的年龄都不大于18
    boolean b3 = getStream().noneMatch(t -> t.age > 18);
    System.out.println(b3);

    // 返回第一个元素
    Optional<Person> first = getStream().findFirst();
    System.out.println(first);

    // 返回当前流中任意元素(在parallelStream下使用)
    Optional<Person> any = getStream().findAny();
    System.out.println(any);

    // 返回流中元素的总个数
    long count = getStream().count();
    System.out.println(count);

    // 返回流中最大值
    Optional<Person> max = getStream().max((o1, o2) -> Integer.compare(o1.age, o2.age));
    System.out.println(max);

    // 返回流中最小值
    Optional<Person> min = getStream().min((o1, o2) -> Integer.compare(o1.age, o2.age));
    System.out.println(min);
}

public static Stream<Person> getStream() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小张", 32));
    list.add(new Person("小王", 12));
    return list.stream();
}

4.2 归约

  • T reduce(T identity, BinaryOperator<T> accumulator); 可以将流中元素反复结合起来,得到一个值
  • Optiona\l reduce(BinaryOperator<T> accumulator); 可以将流中元素反复结合起来,得到一个值
public void test6() {
    // 计算1~10的自然数的总和
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Integer reduce = list.stream().reduce(0, Integer::sum);
    System.out.println(reduce);

    // 计算年龄的总和
    Stream<Integer> ageStream = getStream().map(t -> t.age);
    Optional<Integer> ageSum = ageStream.reduce(Integer::sum);
    System.out.println(ageSum);
}

4.3 收集

  • <R, A> R collect(Collector<? super T, A, R> collector);
// 将年纪大于20岁的人,存入一个集合中
List<Person> collect = getStream().filter(t -> t.age > 20).collect(Collectors.toList());
System.out.println(collect);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章