Java Stream流
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流详解
Java Stream流的更多相关文章
- 一文带你入门Java Stream流,太强了
两个星期以前,就有读者强烈要求我写一篇 Java Stream 流的文章,我说市面上不是已经有很多了吗,结果你猜他怎么说:"就想看你写的啊!"你看你看,多么苍白的喜欢啊.那就&qu ...
- 全面吃透JAVA Stream流操作,让代码更加的优雅
全面吃透JAVA Stream流操作,让代码更加的优雅 在JAVA中,涉及到对数组.Collection等集合类中的元素进行操作的时候,通常会通过循环的方式进行逐个处理,或者使用Stream的方式进行 ...
- Java Stream 流如何进行合并操作
1. 前言 Java Stream Api 提供了很多有用的 Api 让我们很方便将集合或者多个同类型的元素转换为流进行操作.今天我们来看看如何合并 Stream 流. 2. Stream 流的合并 ...
- Java Stream 流(JDK 8 新特性)
什么是 Steam Java 8 中新增了 Stream(流)来简化集合类的使用,Stream 本质上是个接口,接口中定义了很多对 Stream 对象的操作. 我们知道,Java 中 List 和 S ...
- Java | Stream流、泛型、多线程 | 整理自用
1.lambda 表达式 lambda 的延迟执行 可以对程序进行优化,尤其是使用 if {} else {} 条件判断,先判断条件是否成立,再传入计算好的参数. functionName( para ...
- 深度掌握 Java Stream 流操作,让你的代码高出一个逼格!
概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选.排序.聚合等. Stream 的操作符大体上分为两种:中间操作符和终止操作符 中 ...
- Java Stream流的使用
流相关的方法可以分为三种类型,分别是:获取Stream流.中间方法.终结方法.中间方法会返回当前流,可以方便的进行链式调用. 流不可重复使用,否则会报错: java.lang.IllegalState ...
- Java Stream流排序null以及获取指定条数数据
Java8的Stream流的一些用法, //排序 carerVehEntityList = carerVehEntityList.stream().sorted( Comparator.compari ...
- Java Stream简介, 流的基本概念
在Javaor .net编程中, 我们经常见到"stream" 这个字眼. 我们大概知道这是个流的意思, 如果看完本文的话, 应该会有1个大概的概念. 一, Java中什么是St ...
- Java Stream 自定义Collector
Collector的使用 使用Java Stream流操作数据时,经常会用到各种Collector收集器来进行数据收集. 这里便深入了解一点去了解Collector的工作原理和如何自定义Collect ...
随机推荐
- springboot项目记录2用户注册功能
七.注册-业务层 7.1规划异常 7.1.1用户在进行注册的时候,可能会产生用户名被占用的错误,抛出一个异常: RuntimeException异常,作为该异常的子类,然后再去定义具体的异常类型继承这 ...
- Java流程控制1
Scanner对象 java.util.Scanner 通过Scanner类来获取用户输入 next()和nextline()来获取输入的字符串,读取前我们一般需要使用hasnext()和hasnex ...
- C语言初级阶段8——预处理
C语言初级阶段8--预处理 预定义符号 1.概念:预处理是编译之前做的一些事. 2.常用的预定义符号: 注意:: (1)-(4)的格式占位符都用%是,如:printf("%s",D ...
- AcWing 66. 两个链表的第一个公共结点 (2012算法题)
题目: 输入两个链表,找出它们的第一个公共结点. 当不存在公共节点时,返回空节点. 数据范围 链表长度 [1,2000]. 保证两个链表不完全相同,即两链表的头结点不相同. 样例 给出两个链表如下所 ...
- "蔚来杯"2022牛客暑期多校训练营1 C.Grab the Seat!
C.Grab the Seat! 题目链接 https://ac.nowcoder.com/acm/contest/33186/C 题目大意 1.二维平面中,(0,1) - (0,m)为屏幕 2.有n ...
- 第十二组 -摩天脆脆冰淇淋队-第四次团队作业:Git实战
这个作业属于哪个课程 至诚软工实践F班 - 福州大学至诚学院 - 班级博客 - 博客园 (cnblogs.com) 这个作业要求在哪里 第四次团队作业:Git实战 - 作业 - 至诚软工实践F班 - ...
- jquery 时间戳转化为日期时间格式,年月日 时分秒
<script type="text/javascript"> var strDate = ''; $(function(){ // 获取时间戳 时间戳为10位需*10 ...
- windows server 2012 AD域服务器的搭建安装 子域的创建加入 客户机加入域环境(Active Directory域)
1,安装Active Directory域前的准备工作 2,安装Active Directory域 3,加入子域(可选) 4,加入客户机 ******************************* ...
- pytesseract文字识别
import pytesseract from PIL import Image im=Image.open('image.png') print(pytesseract.image_to_strin ...
- samba缓存问题
samba 在第一次登录时,会在windows上缓存着登录密码,当你重新修改samba服务端的密码, 再次登录时,windows会自动用缓存的旧密码登录,导致的登录失败.