千家信息网

Java8 Stream API有什么作用

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章主要介绍"Java8 Stream API有什么作用",在日常操作中,相信很多人在Java8 Stream API有什么作用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对
千家信息网最后更新 2026年11月01日Java8 Stream API有什么作用

这篇文章主要介绍"Java8 Stream API有什么作用",在日常操作中,相信很多人在Java8 Stream API有什么作用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Java8 Stream API有什么作用"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

Stream API 作用

为集合而生,简化集合操作、支持集合并发操作。

从迭代器到Stream

String contents = new String(Files.readAllBytes(Paths.get(alice.txt)), StandardCharsets.UTF_8);List words = Arrays.asList(contents.split("[\\P{L}]+"));

迭代器

int count = 0;for (String w : words) {        if (w.length() > 12) count++;}

Stream

long count = words.stream().filter(w -> w.length() > 12).count();// 并发统计很容易,如下只需要将stream()换成parallelStream()即可:long count = words.parallelStream().filter(w -> w.length() > 12).count();

Stream与集合的区别

  • Stream自己不会存储元素,元素被存放于底层集合中或者根据需要被产生出来;

  • Stream操作符不会改变源Stream对象,它会返回一个持有结果新Stream对象;

  • Stream操作符可能是延迟执行的,这意味着它们会等到需要结果的时候才执行。例如只需要前5个长单词,那么filter方法将在第5次匹配后停止过滤。

Stream使用流程

  1. 创建一个Stream(从集合、数组、迭代器、生成器等数据结构);

  2. 通过一个或者多个Stream操作符,将初始Stream转换为另一个Stream;

  3. 使用一个Stream终止操作符来产生一个结果,该操作会强制它之前的操作立即执行,且在此之后,该Stream就不会再被使用了。

创建Stream

  • 集合:Collection的stream()方法,会产生一个Stream对象;

  • 数组:Stream.of(T... values) 接受一个可变长度参数列表,参数可以是一个数组或者多个同类型独立元素,产生一个Stream对象;

  • Arrays.stream(array, from, to)将数组的一部分转化为Stream;

  • 空Stream:Stream silence = Stream.empty();

  • 无限Stream:
    Stream echos = Stream.generate(() -> "Echo");
    Stream randoms = Stream.generate(Math::random);
    Stream integers = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));

  • JDK示例:
    Stream words = Pattern.compile("[\\P{L}]+").splitAsStream(contents);
    Stream lines = Files.lines(path);

操作Stream

常见Stream操作函数

  • filter:过滤元素,并产生一个新的Stream对象;

  • map:转换;

  • flatMap:一对多转换,即每个元素映射的结构都是另一个Stream,最终将所有Stream合并为一个Stream;

示例

// filter:只获取长单词List wordList = ... ;Stream words = wordList.stream();Stream longWords = words.filter(w -> w.length() > 12);
// map:将所有单词转换为小写Stream lowercaseWords = words.map(w -> w.toLowerCase()); // 或者使用方法引用Stream lowercaseWords = words.map(String::toLowerCase()); // 获取每个单词的首字母  Stream firstChars = words.map(w -> w.charAt(0));
// flatMap:获取每个单词中的字母Stream letters = words.flatMap(w -> Arrays.stream(s.toCharArray()));

Stream提取与组合

  • Stream.limit(n),返回一个包含源Stream前n个元素的新Stream,如果源Stream长度m小于n则返回前m个元素;

  • Stream.skip(n),丢弃掉源Stream的前n个元素,返回包含剩余元素的新Stream;

  • 组合两个Stream为一个新的Stream,假设stream1和stream2为两个Character的Stream:Stream combined = Stream.concat(stream1, stream2);

  • Stream.peek(action),会产生另一个与源Stream具有相同元素的Stream,但是在获取每个元素时,都会调用action参数指定的函数,这样是为了便于调试。

Stream有状态转换

Stream的filter和map、flatMap等操作都是无状态的转换,因为在转换每一个元素时无需考虑之前转换过的元素;
Stream的distinct操作,会根据源Stream中的元素,返回一个元素顺序相同,但是没有重复元素的新Stream,是有状态的转换,因为它在转换每个元素时都需要检查该元素是否之前已读取过。

Stream聚合操作

Stream的聚合操作会将Stream聚合成为一个值,以便程序中使用,例如Stream.count()、Stream.max()、Stream.min()、Stream.findFirst()、Stream.findAny()等。
聚合方法都是终止操作,执行后流就关闭了,不能再应用其它操作了。

聚合操作示例:

Optional longest = words.max(String::compareToIgnoreCase);if (longest.isPresent()) {        Sysout.out.println(longest.get());}
Optional startWithQ = words.filter(s -> s.startsWith("Q")).findFirst();
// 并行提高执行效率Optional startWithQ = words.parallel().filter(s -> s.startsWith("Q")).findAny();
// 并行提高执行效率Optional startWithQ = words.parallel().anyMatch(s -> s.startsWith("Q"));

终止Stream

一个Stream对象在执行终止操作后,就不能再执行其他操作了。

Optional类型

Optional对象是对T类型对象的封装,或者表示不是任何对象。
Optional类本身实现非常简单,常用操作有:

  1. of(T value)

  2. ofNullable(T value)

  3. isPresent()

  4. ifPresent(consumer)

  5. orElse(T other)

  6. orElseGet(Supplier other)

  7. map(Function mapper)

  8. flatMap(Function mapper)用于组合可选函数,例如,如果f()返回Optional,T有一个返回Optional的方法g(),就可以组合调用:Optional op = f().flatMap(T::g)
    用法和其余的看源码最直观。

Stream聚合操作

聚合,即将Stream中的元素聚合成为一个值,例如:求和、求积、计数、字符串追加、最大值、最小值、并积、交积等,只要操作数x,y,z之间有一个操作op,满足(x op y) op z = x op (y op z),那么op操作就是可聚合的;

聚合示例

// 求和Stream values = ...;Optional sum = values.reduce((x, y) -> x + y);// 如果有一个标识e,使得e op x = x,那么标识e就可以作为计算的起点,对于加法来说0就是这个标识,所以另外一种形式:Optional sum = values.reduce(0, (x, y) -> x + y);// 或者Optional sum = values.reduce(0, Integer::sum);
// 求字符串Stream中所有字符串总长度Stream words = ...;Optional sum = words.reduce(0, (total, word) -> total + word.length(), (total1, total2) - > total1 + total2);// 第二个参数accumulator,是为了聚合计算;// 第三个参数combiner,是为了并行聚合计算后,对并行结果进行再聚合;

Stream收集结果

流处理完成以后,我们对于处理结果有两种用途:

  • 执行聚合操作,将整个Stream聚合成为一个值,例如:sum、count、max、min等;

  • 收集Stream处理结果,获取Stream中的每个元素,或打印、或转储、或执行其他计算;

第二种"收集Stream处理结果",由两种操作:

  • collect,两种方式:

  1. R collect(Collector collector); // 使用一个现成的预定义的Collector进行收集,Collectors工具类还为各种常用的收集类型提供了各个工厂方法。

示例1:
Stream stream = ...;
List list = stream.collect(Collectors.toList());
Set set = stream.collect(Collectors.toSet());
TreeSet treeSet = stream.collect(Collectors.toCollection(TreeSet::new));//控制得到的set类型
String result = stream.collect(Collectors.join());//将Stream中所有字符串拼接
String result = stream.collect(Collectors.join(", "));//将Stream中所有字符串拼接且以", " 分隔
// 将Stream结果聚合成为一个包含总和、最大值、最小值、平均值的结果,可以使用Collectors.summaring{Int | Long | Double}方法中的一种,这些方法会接受一个将Stream对象的元素映射为一个数字的函数,并产生一个{Int | Long | Double}SummaryStatistics类型的结果,其中包含了获取总和、最大值、最小值、平均值:
IntSummaryStatistics summary = words.collect(Collectors.summarizingInt(String::length));
double arerageWordLength = summary.getAverage();
double maxWordLength = summary.getMax();

  1. R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner); // 自定义supplier、accumulator、combiner

supplier - a function that creates a new result container. For a parallel execution, this function may be called multiple times and must return a fresh value each time.
accumulator - an associative, non-interfering, stateless function for incorporating an additional element into a result.
combiner - an associative, non-interfering, stateless function for combining two values, which must be compatible with the accumulator function.
示例:
Stream stream = ...;
HashSet result = stream.collect(HashSet::new, HashSet::add, HashSet::addAll);

  • 遍历获取元素,两种方式:

  • void forEach(Consumer action); 非顺序遍历Stream元素,对于并行stream则并行遍历,顺序无法保证,但能提升遍历效率

  • void forEachOrdered(Consumer action);顺序遍历元素,保证顺序性,但是牺牲了性能

将结果收集到Map中:

// 普通toMap Collector,如果键冲突则会跑出IllegalStateExceptionStream persons = ...;Map idToName = persons.collect(Collectors.toMap(Person::getId, Person::getName));Map idToPerson = persons.collect(Collectors.toMap(Person::getId, Function.identity()));
// 定义键冲突解决策略,保留旧值Stream locales = Stream.of(Locale.getAvailableLocales());Map languages = locales.collect(Collectors.toMap(lan - > lan.getDisplayCountry(),        lan -> lan.getDisplayLanguage(),        (existingValue, newValue) - > existingValue));Map idToPerson = persons.collect(Collectors.toMap(Person::getId, Function.identity()));
// 定义键冲突解决策略,以Set方式保留所有值Stream locales = Stream.of(Locale.getAvailableLocales());Map languages = locales.collect(Collectors.toMap(lan - > lan.getDisplayCountry(),        lan -> Collections.singleton(lan.getDisplayLanguage(),        (existingValue, newValue) - > {                Set mergedSet = new HashSet<>(existingValue);                mergedSet.addAll(newValue);                return mergedSet;        };));
// 通过指定第四个参数,将结果收集到TreeMap中去Stream locales = Stream.of(Locale.getAvailableLocales());Map languages = locales.collect(Collectors.toMap(lan - > lan.getDisplayCountry(),        lan -> lan.getDisplayLanguage(),        (existingValue, newValue) - > existingValue),        TreeMap::new));

分组和分片

预定义的分组分片

  • Collectors.groupingBy
    Stream收集到Map过程中,通过分组,来简化相同键的合并问题,示例如下:
    Map> countryToLocales = locales.collect(Collectors.groupingBy(Locale::getCountry));
    函数Locale::getCountry是进行分组的分类函数。

  • Collectors.partitioningBy
    当分组函数是一个Prdicate函数时,即要将Stream中的元素分为是/非两组时,使用partitioningBy会更高效些,示例如下:
    Map> englishAndOtherLocales = locales.collect(Collectors.partitioningBy(lan -> lan.getLanguage().equals("en")));
    将元素分为两组:一组使用英语,一组使用其他语言。获取英语分组列表:
    List englishLocales = englishAndOtherLocales.get(true);

  • Collectors.groupingByConcurrent
    会获取一个并发Map,当用于并行流时可以并发地插入值。这与toConcurrentMap方法完全类似。

分组分片downstream处理

  • downstream
    方法groupingBy会产生一个值为列表的map的对象,如果希望对这个列表进行转换,例如转为Set,则可基于downstream实现,例如:
    Map> countryToLocaleSet = locales.collect(Collectors.groupingBy(Locale::getCountry, Collectors.toSet()));

  • 其他downstream

  • counting()
    Map countryToLocaleCount = locales.collect(Collectors.groupingBy(Locale::getCountry, Collectors.counting())); // 计算每个国家有多少种语言

  • summing{Int | Long | Double}(ToIntFunction mapper)
    Map stateToCityPopucation = cities.collect(Collectors.groupingBy(City::getState, Collectors.summingInt(City::getPopulation()))); // 计算每个下属所有城市人数总和

  • maxBy(Comparator comparator) 和minBy(Comparator comparator)
    Map stateToLargestCity = cities.collect(Collectors.groupingBy(City::getState, Collectors.maxBy(Comparator.comparing(City::getPopulation)))); // 计算每个州中人口最多的城市

  • mapping(Function mapper, Collector downstream)
    Map> stateToLargestCityName = cities.collect(Collectors.groupingBy(City::getState, Collectors.mapping(City::getName, Collectors.maxBy(Comparator.comparing(String::length)))))// 找出每个州中,名字最长的城市名称
    Map> countryToLanguages = locales.collect(Collectors.groupingBy(Locale::getDisplayCountry, mapping(Locale::getDisplayLanguage, Collectors.toSet())))

  • 如果grouping或者mapping函数的返回结果是int、long、double,可以将元素收集到summaryStatistics对象中:
    Map statistics = locales.collect(Colloctors.groupingBy(Locale::getState, summarizingInt(City::getPopulation)));

  • reducing方法可对downstream元素进行一次普通聚合

  • Collector reducing(BinaryOperator op)

  • Collector reducing(identity, BinaryOperator op)

  • Collector reducing(identity, Function mapper, BinaryOperator op)
    示例:
    Map stateToCityNames = cities.collect(groupingBy(City:getState, reducing("", City::getName, (s, t) -> s.length == 0 ? t : s + "," + t)))
    等价于:
    Map stateToCityNames = cities.collect(groupingBy(City:getState, mapping( City::getName, joining(","))));

原始类型流

背景

将整型收集到一个Stream的流中,需要将每个整数封装成一个包装对象,这是一个低效的做法,double/float/long/short/byte/boolean也一样,所以,Stream API专门设计了IntStream、LongStream、DoubleStream用于存放基本数据类型;

  • IntStream:用于存放int、short、char、byte和boolean类型的值;

  • LongStream:用于存放long型的值;

  • DoubleStream:用于存放double、float类型的值;

示例

  • 创建IntStream,使用IntStream.of和Arrays.stream
    IntStream stream = IntStream.of(1,1,2,3,5);
    int[] array = new int[]{1,1,2,3,5};
    stream = Arrays.stream(array, 0, array.length);

  • IngStream和LongStream的range和rangeClosed方法:
    IntStream zeroTo99 = IntStream.range(0, 100); //不包括上线100
    IntStream zeroTo100 = IntStream.rangeClosed(0, 100);//包括上线100

  • 对于对象流,可使用mapToInt、mapToLong、mapToDouble转换为对应的原始类型的流。例如:
    Stream words = ...;
    IntStream lengths = words.mapToInt(String::length);

  • 原始类型流的常用方法:
    sum、max、min、average、summaryStatistics等。

  • Random类的ints、longs、doubles分别产生对应的原始类型随机数字流。

并行流

  • 默认情况下,除了Collection.parallelStream()外,流操作创建的都是串行流。

  • 开启并行流(在终止方法执行前)

Collection.parallelStream()、Stream.parallel()。

  • 当无需考虑Stream元素顺序时,Stream.unordered() 会使并行操作更好地执行,例如distinct(),因为对于一个有序的流,distinct()操作总会保留所有相同元素的第一个,同样的操作还有limit();

到此,关于"Java8 Stream API有什么作用"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

元素 方法 对象 结果 类型 示例 函数 分组 参数 顺序 作用 单词 字符 字符串 处理 原始 相同 操作符 数组 学习 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 新华互联网科技 深圳恒合互联网络科技有限公司 互联网科技行业发展 互联网科技公司怎么样 火传媒上海互联网科技 互联网科技美容 受益于互联网科技的高速发展 福建科技产业互联网发展 湖南一路畅行互联网科技 阿里互联网科技企业 互联网数据科技专业 工业互联网山东科技大学 互联网科技圈年度人物 伍佰万互联网科技怎么赚钱 深圳无忧互联网科技 广州互联网高科技取餐柜 南京一网一红互联网科技有限公司 九思连强互联网电子科技有限公司 吉林省码上互联网科技电话 恒生科技互联网指数十大成分股 精品咖啡豆 河南云网互联网络科技有限公司 互联网巨头科技公司 朗涯互联网科技 央行互联网金融科技公司 厦门比较好的科技互联网公司 互联网科技与大数据专业 用友工业互联网科技发展 数字互联网科技有限公司 互联网科技自媒体灵感
0