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. jsp第6个作业—jdbc

    UsersDao.java package a; import java.sql.Connection; import java.sql.PreparedStatement; import java. ...

  2. Python自学day03

    1.数据类型 int       1,2,3用于计算 bool    True,False用于判断 str       存储少量数据,用于操作 list       存储大量数据  [1,2,3,'a ...

  3. Do whlie 循环

    Do whlie 循环 ◆对于while语句而言,如果不满足条件,则不能进入循环.但有时候我们需要即使不满足条件,也至少执行-次. ◆do...while循环和while循环相似,不同的是,do... ...

  4. C/C++ 数据结构循环队列的实现

    #include <iostream> #include <Windows.h> using namespace std; #define MAXSIZE 6 typedef ...

  5. springBoot的全局异常处理

    GlobalException.java package com.bank.util; import com.bank.exception.ContentEmpyException; import c ...

  6. Kibana+X-pack安装使用

    安装Kibana 下载解压安装包,一定要装与ES相同的版本 下载地址: https://www.elastic.co/downloads/kibana wget https://artifacts.e ...

  7. F. K-th Power 容斥,莫比乌斯

    F. K-th Power 传送门: 牛客:https://ac.nowcoder.com/acm/contest/34866/F cf:https://codeforces.com/group/5z ...

  8. loadrunner添加/清除 cookies

    web_add_cookie("reloadCount=1;domain={Host}"); 清除 cookies web_cleanup_cookies():

  9. TP5中redirect实现重定向及带参数跳转

    1.控制器 重定向url传参 try{ $result = Db::name('wupin')->insert($ist); if($result){ $this->redirect(ur ...

  10. 微软NewBing真是Niubility

    这是本人2012年的拙作:           晨兮,闻风雨,后而雷鸣电闪.迟不可再三,若故无食.然何如耶?雨大风狂,单车奈何?公交卡空,恐时不予我也.不免叹也,天亦不予我!         而后出, ...