java Stream 流

本文深入讲解Java Stream API的创建、转换、计算等核心概念,包括流的定义、工作流程、并行流使用及Optianal类的应用。涵盖过滤、排序、转化等流操作,以及简单约简和自定义约简等计算方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Stream 流

1. Stream的定义

来自数据源的支持聚合操作的元素序列。

即一个流对外提供接口,接收特定的数据。
数据源:数据结构,数组,文件等。
聚合操作:如filter,map,reduce。find,sorted等。

许多流的操作返回也是一个流,且进行流操作时候,用户感知不到循环遍历。

2. 流的工作流程

  • 流的创建。
  • 流的转换,将流转换为其他流的中间操作。
  • 流的计算结果。这个步骤之后,流就不能用了。

流的创建

1. Collection接口的stream方法。

Stream<String> as = new ArrayList<>().stream();
Stream<String> hs = new HashSet<>().stream();
  • 还有其他子类,如LinkList, LinkSet, TreeSet等。

2. Arrays.stream可以将数组转化为Stream。

Stream<String> b1 = Arrays.stream("a,b,c,d,e", split(","));

3. 利用Stream 类进行转化。

  • of方法,直接将数组转化。
Stream<Integer> c1 = Stream.of(new Integer[5]);
Stream<String>  c2 = Stream.of("a,c,b".split(","));
Stream<String>  c3 = Stream.of("a", "b", "c");
  • empty方法,产生一个空流。
Stream<String> d1 = Stream.empty();
  • generate方法,接收一Lambda表达式。
Stream<String> e1 = Stream.generate(() -> "hello");
Stream<Double> e2 = Stream.genarate(Math::random);
  • iterate方法,接收一个种子,和一个Lambda表达式。
Stream<BigInteger> f1 = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));

4. 基本类型流(只有三种)

  • IntStream, LongStream, DoubleStream。
IntStream s1 = IntStream.of(1,2,3,5);
s1.IntStream.generate(() -> (int)(Math.random()*100));
s1.IntStream.range(1, 5);
s1.Arrays.stream(new int[] {1,2,4});

//将基本类型与包装类的转化。
IntStream s2 = IntStream.of(1,2,4,5);
//基本类转为包装类。
Stream<Integer> s3 = s2.boxed();
//包装类转为基本类。
IntStream s4 = s3.mapToInt(Integer::intValue);

5. 并行流
使得所有中间转化都以并行方式进行。

  • Collections.parallelStream():将集合元素转为一个并行流。
  • Stream.parallel()方法,产生一个并行流。
IntStream s1 = IntStream.range(1, 100000);
Long e1 = s1.parallel().filter(n -> n%2 == 0).count();
System.out.println(e1);

谨慎使用并行流。

  1. 其他类/方法产生Stream流。
  • Files.lines方法
Stream<String> contenrs = Files.lines(Paths.get("文件路径"));
  • Pattern的splitAsStream方法。
Stream<String> words = Pattern.compile(",")splitAsStream("a,b,c");

流的转化

  • 从一种流到另一种流。
  1. 过滤 filter。
    – filter(Prelicate<? super T> predicate),接收一个Lambda表达式,对每一个元素进行判定符合要求的留下。
Stream<Integer> s1 = Stream.of(1,2,3,4,5);
Stream<Integer> s2 = s1.filter(n -> n>2);
s2.forEach(System.out::println);
  1. 去重 distinct。
    – 删除元素中重复的部分。
Stream<Integer> s1 = Stream.of(1,1,2,2,33);
Stream<Integer> s2 = s1.distinct();
s2.forEach(System.out::println);
//1,2,33;
  • 对于对象的判定,先调用hashCode方法,再调用equals方法。
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("Tom", 20));
students.add(new Student("Tom", 20));
students.add(new Student("Peter", 20));
students.add(new Student("Bob", 13));

//先调用对象的hashCode方法,再调用其equals方法进行重判。
Stream<Student> s3 = students.stream().distinct();
s3.forEach(System.out.println);
  1. 排序 sorted。
    – sorted()。
    – 提供Comparator,对流进行排序。
Stream<String> s3 = Stream.of(ppp).sorted(
         Comparator.comparing(String::length));

– 对流的自定义对象元素进行排序时,调用对象的compareTo方法。

Stream<Cat> s4 = cats.stream().sorted();
//调用Cat类中自定义的compareTo方法。
  1. 转化 map。
    – 利用方法引用对流中的每一元素进行函数计算。
Stream<Double> s1 = Stream.of(-1.1,-2,3.3);
Stream<Double> s2 = s1.map(Math::abs);
s2.forEach(System.out::println);
//1.1,2,3.3。

– 利用Lambda表达式对流的每一个元素进行函数计算。

Stream<Integer> s3 = Stream.of(-1,-2,3);
Stream<Integer> s4 = s3.map(n -> n*n);
s4.forEach(System.out::println);
//1,4,9。

– 利用方法引用,对流每一个元素进行计算并返回stream。

String[] planets = new String[]{"Mercury", "Verus", "Earth"};

Stream<Stream<String>> s5 = Stream.of(planets).map(word -> letter(word));
s5.forEach(System.out::println);

public static Stream<String> letter(String word){
    ArrayList<String> list = new ArrayList<>();
    for(int i = 0; i < word.length(); i++){
        list.add(word.substring(i, i+1));
    }
    return list.stream();
}

– 利用方法引用,对流每一个元素进行计算返回stream,并合并。
只需要将上述代码中的map方法换为flatmap方法即可。

  1. 转化
    – 抽取 limit。
    – 跳过skip。
IntStream s1 = IntStream.range(0, 10);
IntStream s2 = S1.limit(8);//0-8
IntStream s3 = s2.skip(3);//3-8

– 连接 concat。
Stream s4 = Stream.concat(letter(“hello”, letter(“world”)));
//‘h’e’l’l’o’w’o’r’l’d’

  1. 其他
    – 额外调试 peek。
    Stream s1 = Stream.iterate(1.0, n -> n*2).peek(n -> System.out.println(n)).limit(5);

Optianal

Optional

  • 一个包装器对象,要么包装了类型T的对象,要么没有包装任何对象。
    – T有值,直接返回T对象,T是null,可以返回一个代替值。

  • Optional创建
    – of方法。
    – empty方法。
    – ofNullable方法,对象可能为null。安全创建。

Optional<String> s1 = Optional.of(new String("abd"));
Optional<String> s2 = Optional.empty();
String s3 = null;
Optional<String> s4 = Optional.ofNullable(s3);
//s3不为null,s4为s3,否则s4为Optional.empty().
  • Optional使用
    – get方法,获取值,不安全。
    – orElse方法,获取值,如果为null,采用代替值。
    – orElseGet方法,获取值,如果为null,采用Lambda表达式值返回。
    – orElseThrow方法,获取值,如果为null,则抛出异常。
    – ifPresent方法,判断是否为空,不为空返回true。
    – isPresent(Consumer),判断是否为空,不为空,进行后续Consumer操作。为空,不进行操作。
    – map(Function),将值传递给Function函数计算。为空则不计算。

流的计算

  • 简单约简(聚合函数)
    – count(),计数。
    – max(Comparator),最大值,需要比较器。
    – min(Comparator), 最小值,需要比较器。
    – findFirst(),找到第一个元素。
    – findAny(),找到任意一个元素。
    – anyMatch(Predicate),有一个元素满足Predicate,则返回true。
    – allMatch(Predicate),所有元素满足Predicate,则返回true。
    – noneMatch(Predicate),没有元素满足Predicate,则返回true。
  • 自定义约简
    – reduce,传递一个二元函数BinaryOperator,对流进行操作。
Integer[] a = new Integer[] {1, 2, 3, 4, 5};

Stream<Integer> s1 = Stream.of(a);
Optional<Integer> sum = s1.reduce(Math::sum);
sum.get().forEach(System.out::println);

Stream<Integer> s2 = Stream.of(a);
Optional<Integer> product = s2.reduce((x, y) -> x*y);
System.out.println(product.get());
  • 查看,遍历元素。
    – iterator(),遍历元素。
    – forEach(Cunsumer),应用一个方法到每一个元素上。
Integer[] a = new Integer[]{1,2,3,4,5};

Stream<Integer> s1 = Stream.of(a);
Iterator<Integer> it = s1.filter(n -> n>2).iterator();
while(it.hasNext()){
    System.out.println(it.next());
}

Stream<Integer> s2 = Stream.of(a);
s2.filter(n -> n<4).forEach(System.out.println);
  • 放到数据结构中。
    – toArray(),结果转为数组中。
    – collect(Collectors.toList()),结果转为List。
    – collect(Collectors.toSet()),结果转为Set。
    – collect(Collectors.toMap()),结果转为Map。
    – collect(Collectors.joinning()),结果连接起来。
Integer[] a = new Integer[] {2,4,6,8};
		
		//将流存储为List
		Stream<Integer> s1 = Stream.of(a);
		List<Integer> list1 = s1.collect(Collectors.toList());
		
		//将流存储为指定的LinkedList
		Stream<Integer> s2 = Stream.of(a);
		List<Integer> list2 = s2.collect(Collectors.toCollection(LinkedList::new));
		
		//将流存储为Set
		Stream<Integer> s3 = Stream.of(a);
		Set<Integer> set1 = s3.collect(Collectors.toSet());
		
		//将流变换为字符流,并连接起来
		Stream<Integer> s4 = Stream.of(a);
		String result = s4.map(String::valueOf).collect(Collectors.joining());
		System.out.println(result); //2468
		
		//将流变换为字符流,并连接起来
		Stream<Integer> s5 = Stream.of(a);
		String result2 = s5.map(String::valueOf).collect(Collectors.joining(","));
		System.out.println(result2); //2,4,6,8
		
		
		
		List<Person> persons = new ArrayList<Person>();
		persons.add(new Person(1, "Jerry"));
		persons.add(new Person(2, "Tom"));
		
		//将流存储为Map
		Stream<Person> s6 = persons.stream();
		Map<Integer, String> map1 = s6.collect(Collectors.toMap(Person::getId, Person::getName));
  • 流的高阶计算,分组groupingBy和分区partitionBy。
  • 以上方法均在java.util.stream.Collectors中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值