Java教程

Java8新特性Stream流

本文主要是介绍Java8新特性Stream流,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1、是什么?

  • Stream(流)是一个来自数据源的元素队列并支持聚合操作

image

2、能干嘛?

  • Stream流的元素是特定类型的对象,形成一个队列。
  • Java中的Stream并不会存储元素,而是按需计算。
  • 数据源,流的来源。
    • 可以是集合,数组,I/O channel, generator等。
  • 聚合操作,类似SQL语句一样的操作:
    • 比如filter, map, reduce, find, match, sorted等。
  • 和以前的Collection操作不同, Stream操作还有两个基础的特征:
    • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
    • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

3、怎么玩?

1、创建Stream的方式(原材料)

package com.qbb.threadpool;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author QiuQiu&LL (个人博客:https://www.cnblogs.com/qbbit)
 * @version 1.0
 * @date 2022-07-23  20:19
 * @Description:
 */
public class Java8NewFeatureStream {
    public static void main(String[] args) {

        // 创建Stream方式一 : 通过集合
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        // 获取串行流
        Stream<Integer> stream = list.stream();
        // 获取一个并行流
        Stream<Integer> parallelStream = list.parallelStream();

        // 创建Stream方式二 : 通过数组
        String[] arr = new String[]{"a", "b", "c"};
        Stream<String> arrStream = Arrays.stream(arr);

        // 创建Stream方式三 : 通过Stream.of()
        Stream<String> streamOf = Stream.of("x", "y", "z");

        // 创建Stream方式四 : 通过Stream.iterate(),创建无限流
        Stream<Integer> integerStream = Stream.iterate(0, q -> q + 1).limit(5);
        integerStream.forEach(System.out::println);

        //生成10个随机数
        Stream<Double> stream1 = Stream.generate(Math::random).limit(10);
        stream1.forEach(System.out::println);
    }
}

2、中间操作(车间加工)

(1)fifter(Predicate<? super T> predicate) : 过滤,保留满足条件分元素

public static void main(String[] args) {
	// 创建流
	List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6);
	asList.stream()
		.filter(q -> q % 2 ==0) // filter:过滤,保留符合条件的元素
		.forEach(System.out::println); // forEach:内部迭代,终止操作输出每一个元素

}

image

(2) distinct () : 去除重复的元素

// 测试类
class User {
    private String name;
    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age && Objects.equals(name, user.name);
    }

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

public static void main(String[] args) {
        // 创建流
        List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 5);
        asList.stream().distinct().forEach(System.out::println);

        List<User> userList = new ArrayList<>();
        // 测试一下对象类型
        for (int i = 0; i < 5; i++) {
            User user = new User("qiuqiu"+i,18+i);
            userList.add(user);
        }
        User qiuqiu3 = new User("qiuqiu3", 21);
        userList.add(qiuqiu3);
        userList.stream().distinct().forEach(System.out::println);
    }

image

(3)limit(long maxSize) : 获取指定maxSize个元素

public static void main(String[] args) {
        // 创建流
        List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 5);
        asList.stream().limit(3).forEach(System.out::println);
    }

image

(4) skip(long n) : 跳过前n个元素

public static void main(String[] args) {
        // 创建流
        List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 5);

        long count = asList.stream()
                .skip(3) // 跳过前三个元素
                // .findFirst() // 获取跳过操作后的第一个元素
                // .findAny() // 获取跳过操作后的任意一个元素
                .count(); // 获取剩余元素个数
        // System.out.println("result = " + result);
        System.out.println("count = " + count);
    }

image

(5) sorted()/sorted(Comparator<? super T> comparator) : 排序

public static void main(String[] args) {
        // 创建流
        List<Integer> asList = Arrays.asList(4, 5, 6, 2, 1, 2, 3, 5);
        // 默认排序
        asList.stream().sorted().forEach(System.out::println);

        System.out.println("=======================================================");
        // 指定比较器排序
        // asList.stream().sorted((o1,o2) -> o1.compareTo(o2)).forEach(System.out::println);
        asList.stream().sorted(Integer::compareTo).forEach(System.out::println);
    }

(6) map :接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

public static void main(String[] args) {
        // 创建流
        List<Integer> asList = Arrays.asList(4, 5, 6, 2, 1, 2, 3, 5);
        // map
        asList.stream().map(q -> {
            String str;
            if(q%2 == 0){
                str = q+"qiu";
            }else {
                str = q + "ll";
            }
            return str;
        }).forEach(System.out::println);
    }

image

  • 其他的一些操作
  • mapToInt(ToIntFunction<? super T> mapper)
  • mapToDouble(ToDoubleFunction<? super T> mapper)
  • mapToLong(ToLongFunction<? super T> mapper)
  • flatMapToInt(Function<? super T, ? extends IntStream> mapper)
  • flatMapToLong(Function<? super T, ? extends LongStream> mapper)
  • flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper)

(7) flatMap :接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

public static void main(String[] args) {
        // 创建流
        String[] arr = new String[]{"a,b,c","x,y,z"};
        // flatMap
        Arrays.stream(arr).flatMap(q -> {
            String[] split = q.split(",");
            // 把一个流拆分多个流然后又合并为一个流
            Stream<String> stream = Arrays.stream(split);
            return stream;
        }).forEach(System.out::println);
    }

image

(8) peek :如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。

public static void main(String[] args) {
        // 创建流
        User zs = new User("zs", 18);
        User ls = new User("ls", 28);

        List<User> userList = Arrays.asList(zs, ls);
        userList.stream()
                .peek(q -> q.setAge(22))
                .forEach(System.out::println);
    }

image

当然还有其他的一些操作,这里就不一一演示了

3、终止操作

(1)匹配、聚合操作

allMatch :接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false
noneMatch :接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
anyMatch :接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
findFirst :返回流中第一个元素
findAny :返回流中的任意元素
count :返回流中元素的总个数
max :返回流中元素最大值
min :返回流中元素最小值

public static void main(String[] args) {
        // 创建流
        List<Integer> asList = Arrays.asList(4, 5, 6, 2, 1, 2, 3, 5);

        boolean allMatch = asList.stream().allMatch(q -> q > 0);
        System.out.println("allMatch = " + allMatch);

        boolean noneMatch = asList.stream().noneMatch(q -> q < 0);
        System.out.println("noneMatch = " + noneMatch);

        boolean anyMatch = asList.stream().anyMatch(q -> q % 2 == 0);
        System.out.println("anyMatch = " + anyMatch);

        Integer findFirst = asList.stream().findFirst().get();
        System.out.println("findFirst = " + findFirst);

        Integer findAny = asList.stream().findAny().get();
        System.out.println("findAny = " + findAny);

        // long count = asList.stream().count();
        long count = asList.size();
        System.out.println("count = " + count);

        Integer max = asList.stream().max(Comparator.comparingInt(o -> o)).get();
        System.out.println("max = " + max);

        Integer min = asList.stream().min(Integer::compareTo).get();
        System.out.println("min = " + min);

    }

image

(2) 规并操作

Optional<T> reduce(BinaryOperator<T> accumulator) :第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推。
T reduce(T identity, BinaryOperator<T> accumulator) :流程跟上面一样,只是第一次执行时,accumulator函数的第一个参数为identity,而第二个参数为流中的第一个元素。
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner) :在串行流(stream)中,该方法跟第二个方法一样,即第三个参数combiner不会起作用。在并行流(parallelStream)中,我们知道流被fork join出多个线程进行执行,此时每个线程的执行流程就跟第二个方法reduce(identity,accumulator)一样,而第三个参数combiner函数,则是将每个线程的执行结果当成一个新的流,然后使用第一个方法reduce(accumulator)流程进行规约。

public static void main(String[] args) {
        // 创建流
        List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5);
        Integer one = asList.stream().reduce(Integer::sum).get();
        System.out.println("one = " + one);

        Integer two = asList.stream().reduce(100, Integer::sum);
        System.out.println("two = " + two);

        Integer three = asList.parallelStream().reduce(100,
                Integer::sum,
                (x, y) -> x * y);
        System.out.println("three = " + three);
    }

image

(3) 收集操作

collect :接收一个Collector实例,将流转化为其他形式,常用的List、Set、Map、Collection。

  • 内部通过Collectors这个类进行相应的操作

(4) Collectors相关操作

toCollection toList() toSet() toMap : 将输入元素累积到一个集合中
public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

        list.replaceAll(q -> q > 5 ? q + 10 : q);
        System.out.println("list = " + list);
        list.sort((o1, o2) -> o1 - o2);
        // 转Collection
        Collection<Integer> collection = list.parallelStream().collect(Collectors.toCollection(HashSet::new));
        // 转List
        List<Integer> integerList = list.parallelStream().collect(Collectors.toList());
        // 转Set
        Set<Integer> set = list.parallelStream().collect(Collectors.toSet());
        // 转Map
        Map<Integer, Integer> map = list.parallelStream().collect(Collectors.toMap(item -> item, integer -> integer));
    }

joining : 连接字符串
// joining
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f", "g");
String result = list.parallelStream().collect(Collectors.joining(",", "[", "]"));
System.out.println("result = " + result);
mapping/flatMapping : 它将Function应用于输入元素,然后将它们累积到给定的Collector
Set<String> setStr = Stream.of("a", "a", "b")
		.collect(Collectors.mapping(String::toUpperCase, Collectors.toSet()));
System.out.println(setStr); // [A, B]

Set<String> setStr1 = Stream.of("a", "a", "b")
		.collect(Collectors.flatMapping(s -> Stream.of(s.toUpperCase()), Collectors.toSet()));
System.out.println(setStr1); // [A, B]
collectingAndThen : 返回一个收集器,该收集器将输入元素累积到给定的收集器中,然后执行其他完成功能
List<String> strList2 = Lists.newArrayList("1", "2", "10", "100", "20", "999");

List<String> unmodifiableList = strList2.parallelStream()
		.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
System.out.println(unmodifiableList); // [1, 2, 10, 100, 20, 999]
counting : 计数
Long evenCount = Stream.of(1, 2, 3, 4, 5).filter(x -> x % 2 == 0).collect(Collectors.counting());
System.out.println(evenCount); // 2
minBy : 根据给定的比较器返回最小元素
Optional<Integer> min = Stream.of(1, 2, 3, 4, 5).collect(Collectors.minBy((x, y) -> x - y));
System.out.println(min); // Optional[1]
maxBy : 它根据给定的比较器返回最大元素
Optional<Integer> max = Stream.of(1, 2, 3, 4, 5).collect(Collectors.maxBy((x, y) -> x - y));
		System.out.println(max); // Optional[5]
summingInt/summingLong/summingDouble : 求总和
List<String> strList3 = Arrays.asList("1", "2", "3", "4", "5");
Integer sum = strList3.parallelStream().collect(Collectors.summingInt(Integer::parseInt));
System.out.println(sum); // 15

Long sumL = Stream.of("12", "23").collect(Collectors.summingLong(Long::parseLong));
System.out.println(sumL); // 35

Double sumD = Stream.of("1e2", "2e3").collect(Collectors.summingDouble(Double::parseDouble));
System.out.println(sumD); // 2100.0
averagingInt/averagingLong/averagingDouble : 求平均值
List<String> strList4 = Arrays.asList("1", "2", "3", "4", "5");
Double average = strList4.parallelStream().collect(Collectors.averagingInt(Integer::parseInt));
System.out.println(average); // 3.0

Double averageL = Stream.of("12", "23").collect(Collectors.averagingLong(Long::parseLong));
System.out.println(averageL); // 17.5

Double averageD = Stream.of("1e2", "2e3").collect(Collectors.averagingDouble(Double::parseDouble));
System.out.println(averageD); // 1050.0
groupingBy : 分组
Map<Integer, List<Integer>> mapGroupBy = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.groupingBy(x -> x * 10));
System.out.println(mapGroupBy); // {50=[5], 20=[2], 40=[4, 4], 10=[1], 30=[3, 3]}
groupingByConcurrent : 分组,是并发和无序的
Map<Integer, List<Integer>> mapGroupBy = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.groupingByConcurrent(x -> x * 10));
System.out.println(mapGroupBy); // {50=[5], 20=[2], 40=[4, 4], 10=[1], 30=[3, 3]}
partitioningBy : 返回一个Collector,它根据Predicate对输入元素进行分区,并将它们组织成Map <Boolean,List >
Map<Boolean, List<Integer>> mapPartitionBy = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.partitioningBy(x -> x % 2 == 0));
System.out.println(mapPartitionBy); // {false=[1, 3, 5, 3], true=[2, 4, 4]}
BinaryOperator : 返回一个收集器,它在指定的BinaryOperator下执行其输入元素的减少。这主要用于多级缩减,例如使用groupingBy()和partitioningBy()方法指定下游收集器
Map<Boolean, Optional<Integer>> reducing = Stream.of(1, 2, 3, 4, 5, 4, 3).collect(Collectors.partitioningBy(
		x -> x % 2 == 0, Collectors.reducing(BinaryOperator.maxBy(Comparator.comparing(Integer::intValue)))));
System.out.println(reducing); // {false=Optional[5], true=Optional[4]}
summarizingInt : 返回统计数据:min, max, average, count, sum
IntSummaryStatistics summarizingInt = Stream.of("12", "23", "35")
    .collect(Collectors.summarizingInt(Integer::parseInt));
System.out.println(summarizingInt);
//IntSummaryStatistics{count=3, sum=70, min=12, average=23.333333, max=35}
这篇关于Java8新特性Stream流的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!