Java8 Stream流编程

Stream 使用一种类似于SQL语句从数据库查询数据的直观方式来提供对 Java 集合运算和表达的高阶抽象。得益于 Lambda 所带来的函数式编程,Stream API 可以极大的提高 Java 程序员的生产力。关于函数式编程可以查看我的另一篇博客 Java 函数式接口

什么是 Stream 流

A sequence of elements supporting sequential and parallel aggregate operations.

翻译过来就是一个支持串行和并行聚合操作的元素序列:

  • 序列中的元素是一个特定类型的对象,Stream 本身并不会存储任何元素,而是按需计算
  • 序列的来源可以是集合、数组、I/O channel等
  • 聚合操作是类似 SQL 语句的操作,如 fiter, map, distinct, sorted 等

获取 Stream 流

  • stream():创建串行流
  • parallelStream():创建并行流

Java 数组

// 基本类型数组,使用 Arrays.stream() 获取流,类似的还有 LongStream, DoubleStream
int[] nums = {1, 2, 3}
IntStream intStream = Arrays.stream(arr); // 对象类型数组,使用 Stream.of() 获取流
String[] array = {"a", "b", "c"};
// Stream.of() 内部还是调用的 Arrays.stream(T[] values)
Stream<String> stream = Stream.of(array);

Java 集合

// 集合类型获取串行流
List<Integer> list = new ArrayList<>();
Stream<Integer> stream = list.stream(); // 集合类型获取并行流
// 方法一:直接获取
// 方法二:从串行流转换
Stream<Integer> parallelStream = list.parallelStream();
Stream<Integer> parallelStream = list.stream().parallel(); Set<Integer> set = new HashSet<>();
Stream<Integer> stream2 = set.stream(); Stack<Integer> stack = new Stack<>();
Stream<Integer> stream3 = stack.stream();

Java Map

Map<String, String> map = new HashMap<>();
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
Stream<String> keyStream = map.keySet().stream();
Stream<String> valueStream = map.valueSet().stream();

Java Stream 的使用

数组元素求和

// 传统做法
int[] nums = {1, 2, 3, 4, 5};
int sum = 0;
for (int num : nums) {
sum += nums;
} // 使用 Stream 求和
int sum = Arrays.stream(nums).sum();

集合遍历过滤

List<String> list = new ArrayList<>();
list.add("ab");
list.add("abc");
list.add("aefg");
list.add("hijkl"); // 传统方法
List<String> startWithA = new ArrayList<>();
for (String temp : list) {
if (temp.startsWith("a")) {
startWithA.add(temp);
}
} List<String> longList = new ArrayList<>();
for (String temp : startWithA) {
if (temp.length() >= 4) {
longList.add(temp);
}
} // Stream 方法
List<String> filtered = list.stream().filter(s -> s.startsWith("a"))
.filter(s -> s.length() >= 4)
.collect(Collectors.toList());

Stream 风格可以使得 Java 代码干净、简洁,这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理。

从上面的例子可以看出 Stream 操作有以下两个特征:

  • 中间操作会返回流对象本身,多个操作可以串联成一个管道,如同流式风格
  • 传统集合遍历都是通过迭代器或者For-Each的方式在集合外部进行迭代,Stream 提供了内部迭代的方式,通过访问者模式实现

Java Stream 常用方法分析

filter() 方法

将 Stream 流转换成一个子集流。

/**
* Returns a stream consisting of the elements of this stream
* that match the given predicate.
*/
Stream<T> filter(Predicate<? super T> predicate); // Example
String[] array = {"a", "bc", "def", "ghij"};
Stream<String> stream = Stream.of(array); // 子集流中包括元素 "def", "ghij"
Stream<String> subStream = stream.filter(s -> s.length() >= 3);

map() 方法

将 Stream 流中的元素映射到另一个流中。

/**
* Returns a stream consisting of the results of applying the given
* function to the elements of this stream.
*/
<R> Stream<R> map(Function<? super T, ? extends R> mapper); // Example
String[] array = {"a", "bc", "def", "ghij"};
Stream<String> stream = Stream.of(array); // 流中包括array每个字符串的长度,{1, 2, 3, 4}
Stream<Integer> mapStream = stream.map(s -> s.length());

distinct() 方法

对 Stream 流中的元素做去重处理。

/**
* Returns a stream consisting of the distinct elements (according to
* {@link Object#equals(Object)}) of this stream.
*/
Stream<T> distinct(); // Example
String[] array = {"a", "bc", "def", "bc", "a"};
Stream<String> stream = Stream.of(array); // "a", "bc" 是重复元素, distinct处理后流中只会保留一个
Stream<String> distinctStream = stream.distinct();

sorted() 方法

对 Stream 流中的元素排序。

/**
* Returns a stream consisting of the elements of this stream, sorted
* according to natural order. If the elements of this stream are
* not{@code Comparable}, a {@code java.lang.ClassCastException} may
* be thrown when the terminal operation is executed.
*/
Stream<T> sorted(); // Example
String[] array = {"a", "cc", "ab", "b", "c"};
Stream<String> stream = Stream.of(array); // 流中的元素按字典顺序升序排列
// {"a", "ab", "b", "c", "cc"}
Stream<String> sortedStream = stream.sorted(); /**
* Returns a stream consisting of the elements of this stream, sorted
* according to the provided {@code Comparator}.
* 自定义排序规则
*/
Stream<T> sorted(Comparator<? super T> comparator); // 流中的元素按长度升序排列
// {"a", "b", "c", "ab", "cc"}
Stream<String> sortedStream = stream.sorted((o1, o2) -> o1.length() - o2.length());

limit() 方法

截取流中的元素,取前 maxSize 个元素。

/**
* Returns a stream consisting of the elements of this stream,
* truncated to be no longer than {@code maxSize} in length. Stream<T>
* limit(long maxSize);
*/
Stream<T> limit(long maxSize); // Example
String[] array = {"a", "cc", "ab", "b", "c"};
Stream<String> stream = Stream.of(array); // 截取流中前3个元素,{"a", "cc", "ab"}
Stream<String> limitStream = stream.limit(3);

skip() 方法

跳过前 n 个元素,如果原 Stream 流中元素个数小于 n,则返回一个空的 Stream 流。

 /**
* Returns a stream consisting of the remaining elements of this
* stream after discarding the first {@code n} elements of the
* stream.
* If this stream contains fewer than {@code n} elements then an
* empty stream will be returned.
*/
Stream<T> skip(long n); // Example
String[] array = {"a", "cc", "ab", "b", "c"};
Stream<String> stream = Stream.of(array); // 跳过流中前3个元素,返回 {"b", "c"}
Stream<String> skipStream = stream.skip(3);
// 跳过流中前5个元素,返回 {}
Stream<String> skipStream = stream.skip(3);

forEach() 方法

将每一个流元素交给 action 中的方法处理。

forEach 与 forEachOrdered

  • 串行流,两者的效果一致,都是对流中的元素顺序执行 action 中的操作
  • 并行流,forEach操作元素不一定按顺序执行,而forEachOrdered则保证元素按顺序执行
/**
* Performs an action for each element of this stream.
*/
void forEach(Consumer<? super T> action); /**
* Performs an action for each element of this stream, in the
* encounter order of the stream if the stream has a defined
* encounter order.
*/
void forEachOrdered(Consumer<? super T> action); // Example
String[] array = {"a", "cc", "ab", "b", "c"};
Stream<String> stream = Stream.of(array); // 顺序输出流中的元素,{"a", "cc", "ab", "b", "c"}
stream.forEach(s -> System.out.println(s));
stream.forEachOrdered(s -> System.out.println(s));

toArray() 方法

返回一个数组,包含 Stream 流中的元素。

/**
* Returns an array containing the elements of this stream.
*/
String[] array = {"a", "cc", "ab", "b", "c"};
Stream<String> stream = Stream.of(array); // 将原Stream流中的元素去重后转换为数组
String[] array2 = (String[])stream.distinct().toArray();

min(), max() 方法

分别返回 Stream 流中最小的元素,最大的元素。

/**
* Returns the minimum element of this stream according to the
* provided.
*/
Optional<T> min(Comparator<? super T> comparator); // Example
List<Integer> list = new ArrayList<>(); list.add(2);
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> min = list.stream().min((o1, o2) -> o1 - o2);
Optional<Integer> max = list.stream().max((o1, o2) -> o1 - o2); // 1, 4
System.out.println(min.get() + ", " + max.get());

count() 方法

返回 Stream 流中元素的个数。

/**
* Returns the count of elements in this stream.
*/
long count(); List<Integer> list = new ArrayList<>(); list.add(2);
list.add(4);
list.add(1);
list.add(3); // 4
long numbers = list.stream().count();

anyMatch() 方法

Stream 流中存在元素满足 predicate 中的约束,则返回 True

/**
* Returns whether any elements of this stream match the provided
* predicate.
*/
boolean anyMatch(Predicate<? super T> predicate); // Example
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(4);
list.add(1);
list.add(3); boolean flag1 = list.stream().anyMatch(num -> num > 2); // True
boolean flag2 = list.stream().anyMatch(num -> num > 4); // False

allMatch() 方法

Stream 流中所有元素满足 predicate 中的约束,则返回 True

/**
* Returns whether all elements of this stream match the provided
* predicate.
*/
boolean allMatch(Predicate<? super T> predicate); // Example
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(4);
list.add(1);
list.add(3); boolean flag1 = list.stream().allMatch(num -> num > 0); // True
boolean flag2 = list.stream().allMatch(num -> num > 2); // False

concat() 方法

合并两个 Stream 流中的元素。

/**
* Creates a lazily concatenated stream whose elements are all the
* elements of the first stream followed by all the elements of the
* second stream.
*/
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
Objects.requireNonNull(a);
Objects.requireNonNull(b); @SuppressWarnings("unchecked")
Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
(Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
return stream.onClose(Streams.composedClose(a, b));
} // Example
String[] s1 = {"a", "c", "e"};
String[] s2 = {"b", "d", "f"}; // {"a", "c", "e", "b", "d", "f"}
Stream.concat(Stream.of(s1), Stream.of(s2)).forEach(s -> System.out.println(s));

参考文章

[1] Java-Stream流详解

[2] Java 8 Stream 菜鸟教程

Java Stream流的更多相关文章

  1. 一文带你入门Java Stream流,太强了

    两个星期以前,就有读者强烈要求我写一篇 Java Stream 流的文章,我说市面上不是已经有很多了吗,结果你猜他怎么说:"就想看你写的啊!"你看你看,多么苍白的喜欢啊.那就&qu ...

  2. 全面吃透JAVA Stream流操作,让代码更加的优雅

    全面吃透JAVA Stream流操作,让代码更加的优雅 在JAVA中,涉及到对数组.Collection等集合类中的元素进行操作的时候,通常会通过循环的方式进行逐个处理,或者使用Stream的方式进行 ...

  3. Java Stream 流如何进行合并操作

    1. 前言 Java Stream Api 提供了很多有用的 Api 让我们很方便将集合或者多个同类型的元素转换为流进行操作.今天我们来看看如何合并 Stream 流. 2. Stream 流的合并 ...

  4. Java Stream 流(JDK 8 新特性)

    什么是 Steam Java 8 中新增了 Stream(流)来简化集合类的使用,Stream 本质上是个接口,接口中定义了很多对 Stream 对象的操作. 我们知道,Java 中 List 和 S ...

  5. Java | Stream流、泛型、多线程 | 整理自用

    1.lambda 表达式 lambda 的延迟执行 可以对程序进行优化,尤其是使用 if {} else {} 条件判断,先判断条件是否成立,再传入计算好的参数. functionName( para ...

  6. 深度掌握 Java Stream 流操作,让你的代码高出一个逼格!

    概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选.排序.聚合等. Stream 的操作符大体上分为两种:中间操作符和终止操作符 中 ...

  7. Java Stream流的使用

    流相关的方法可以分为三种类型,分别是:获取Stream流.中间方法.终结方法.中间方法会返回当前流,可以方便的进行链式调用. 流不可重复使用,否则会报错: java.lang.IllegalState ...

  8. Java Stream流排序null以及获取指定条数数据

    Java8的Stream流的一些用法, //排序 carerVehEntityList = carerVehEntityList.stream().sorted( Comparator.compari ...

  9. Java Stream简介, 流的基本概念

    在Javaor .net编程中,  我们经常见到"stream" 这个字眼. 我们大概知道这是个流的意思, 如果看完本文的话, 应该会有1个大概的概念. 一, Java中什么是St ...

  10. Java Stream 自定义Collector

    Collector的使用 使用Java Stream流操作数据时,经常会用到各种Collector收集器来进行数据收集. 这里便深入了解一点去了解Collector的工作原理和如何自定义Collect ...

随机推荐

  1. k8s配置拉取镜像密钥

    一.部署步骤 1.创建阿里云镜像仓库 2.创建Secret绑定镜像仓库账号 3.创建Deployment绑定Secret 二.创建阿里云镜像仓库 1.进入阿里云容器镜像服务,创建个人版实例 2.设置登 ...

  2. pytorch 创建图与叶子节点与根节点

    创建时用户直接给出的为叶子节点,没有fn 由几个叶子节点推导来的为最终结果,为root节点,有fn. 譬如: x=tt.tensor([1],dtype='flaot',requires_grad=T ...

  3. 小梅哥课程学习——串口发送应用之发送数据(可在vivado中仿真出现正确波形)

    //1.底层代码源代码发送10位数据 module uart_pr( clk, reset_n, send_go, data, baud_set, tx_done, uart_tx ); input ...

  4. web后端之过滤器

    1直接java搞定 2把@WebFilter()去掉,配置web.xml文件.

  5. 1js 高级

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. Java中int型数据类型对应MySQL数据库中哪种类型?

    java类   mysql数据库 java.lang.Byte byte TINYINT java.lang.Short short SMALLINT java.lang.Integer intege ...

  7. Stream流相关方法

    LIST<对象> 转换MAP 并根据某个字段分组 // 并根据某个字段分组,并做了归类 Map<String, List<User>> collect = user ...

  8. 安装SQL Server 2008 R2出现的问题及解决方法(配合Visual Studio )

    学校的一个作业需要SQL Server,所以就安装一个,没想到还真是有不少问题 总结:遇到问题,取消安装,完全删除(注册表啥的,小心,细心),重新安装. tips:彻底删除SQL Server应用及组 ...

  9. Delphi注解(不是注释)

    开发环境Delphi XE10 1 unit Unit1; 2 3 interface 4 5 uses 6 Winapi.Windows, Winapi.Messages, System.SysUt ...

  10. 使用angular/cli新建一个angular项目

    1.打开cmd,进入你代码保存的文件夹,你想把新建的项目保存在哪个文件夹,即进入哪个文件夹: 我把文件放到这里: 然后,使用下面的命令创建项目: // ng new 项目名称,如下示例:创建名为 he ...