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. ceph PG 故障状态

    PG 故障状态 Creating(创建中)在创建POOL时,需要指定PG的数量,此时PG的状态便处于creating,意思是Ceph正在创建PG Peering(互联中)peering的作用主要是在P ...

  2. 5、什么是MIME

    MIME 类型 媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档.文件或字节流的性质和格式.它在IETF ...

  3. 2003031120—廖威—Python数据分析第七周作业—MySQL的安装以及使用

    项目    内容 课程班级博客链接 https://edu.cnblogs.com/campus/pexy/20sj 这个作业要求链接  https://edu.cnblogs.com/campus/ ...

  4. 解决navicat远程连接MySQL失败,报错1130问题

    1select host from user where user='root'; 2update user set host = '%' where user ='root';3flush priv ...

  5. 服务器DMZ理解

    转别人的 您的公司有一堆电脑,但可以归为两大类:客户机.服务器.所谓客户机就是主动发起连接请求的机器,所谓服务器就是被动响应提供某些服务的机器.服务器又可以分仅供企业内网使用和为外网提供服务两种.   ...

  6. webpack配置跨域proxy

    首先新建一个项目: 安装vue-cli: npm i -g @vue/cli npm i -g @vue/cli-init 安装webpack: npm install webpack -g vue新 ...

  7. linux环境变量配置错误后命令无法使用解决方案

    环境变量配置时多复制了一个空格,导致执行source /etc/profile后提示错误,无法编辑和查看文件 解决方案: 查看当前系统变量:echo $PATH 临时修改:export PATH=/u ...

  8. Selenium协议

    Selenium驱动浏览器使用的协议是什么? JsonWireProtocol 是通过webdriver与remote sever进行通信的web service协议.通过http请求,完成和remo ...

  9. stm32 USART

    stm32 USART 1 USART基础知识 三种模式:轮询模式.中断模式.DMA模式 轮询模式属于阻塞模式 中断模式和DMA模式属于非阻塞模式 发送数据 接收数据 1.1 Polling mode ...

  10. Springboot ehcache/redis双缓存问题

    问题1:两个CacheManager 会报两个相同的实现类错误需要继承CachingConfigurerSupport 重写cacheManager方法,指定默认一个返回缓存提供者 @Configur ...