简介
Java 8 API添加了一个支持对元素流进行函数式操作的类 Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过 中间操作(intermediate operation) 的处理,最后由 终端操作(terminal operation) 得到前面处理的结果。
大多stream操作接受某种形式的lambda表达式作为参数,通过方法接口的形式指定操作的具体行为,这些方法接口的行为基本上都是无干扰(non-interfering)和无状态(stateless)。
- 无干扰(non-interfering):该方法不修改stream的底层数据源。
- 无状态(stateless):操作的执行是独立的,没有lambda表达式在执行中依赖可能发生变化的外部变量或状态。
示例源代码
stream的创建
- 从一个 Collection 的 stream() 和 parallelStream() 方法;
- 从一个数组通过 Arrays.stream(Object[]);
- 来自流类上的静态工厂方法,例如 Stream.of(Object[]), IntStream.range(int, int) 或Stream.iterate(Object, UnaryOperator);
- 文件的行可以从 BufferedReader.lines() 获得;
- 文件路径流可以从 Files 中的方法获得;
- 可以从 Random.ints() 获得随机数流;
- JDK 中的许多其他流承载方法,包括 BitSet.stream()、Pattern.splitAsStream(java.lang.CharSequence) 和 JarFile.stream()。
private static void createStream() {
List<String> list = new ArrayList<String>() {
{
this.add("hi");
this.add("sorry");
this.add("hello");
this.add("word");
}
};
list.stream().map(it -> it + " dd").forEach(System.out::println);
list.parallelStream().map(it -> it + " dd").forEach(System.out::println);
String[] array = new String[]{
"one", "two", "three"
};
Arrays.stream(array).map(it -> it + " dd").forEach(System.out::println);
IntStream.range(1, 5).forEach(System.out::println);
Stream.iterate(1, s -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return s + 1;
}).forEach(System.out::println);
try {
new BufferedReader(new FileReader("./test.txt")).lines().forEach(System.out::println);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
new Random().ints(3, 1, 20).forEach(System.out::println);
}
简单使用
中间操作
- 过滤:
filter(T -> boolean) (非干扰、无状态) - 类型转换:
map(T -> R) 将流中的每一个元素 T 映射为 R (非干扰、无状态) flatMap(T -> Stream) 将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流distinct() 将流中重复的元素去除,去重 (非干扰、有状态)- 根据字段排序
sorted() / sorted((T, T) -> int) (非干扰、有状态) peek(T -> void) 返回由该流的元素组成的流, 这个方法存在主要是为了支持调试,你想要的地方查看流经管道中某个点的元素- 返回前 n 个元素
limit(long n) (短路、有状态) - 跳过前 n 个元素
skip(long n) (有状态)
private static void intermediateOperation() {
String[] array = new String[]{
"one, two", "four, five", "two, three", "three, four", "one, two", "six", "ten", "five", "three"
};
Arrays.stream(array)
.filter(s -> s.startsWith("t"))
.forEach(System.out::println);
Arrays.stream(array)
.map(s -> s.split(","))
.flatMap(Arrays::stream)
.peek(s -> System.out.println("flatMap -> " + s))
.map(String::trim)
.distinct()
.sorted((String::compareTo))
.limit(3)
.skip(1)
.forEach(System.out::println);
}
终端操作
- 遍历操作
forEach(e -> { … }) / forEachOrdered(e -> { … }) toArray() 返回一个包含此流元素的数组。reduce((T, T) -> T) 、 reduce(T, (T, T) -> T) 和 reduce(R, (R, T) -> R, (R, R) -> R) 用于组合流中的元素,如求和,求积,求最大值等collect() 收集方法,我们很常用的是 collect(toList()),当然还有 collect(toSet()) 等,参数是一个收集器接口min() 、max() 、count() 最小值、最大值、流中元素数量anyMatch(T -> boolean) 流中是否有一个元素匹配给定的 T -> boolean 条件allMatch(T -> boolean) 流中是否所有元素都匹配给定的 T -> boolean 条件noneMatch(T -> boolean) 流中是否没有元素匹配给定的 T -> boolean 条件findAny() :找到其中一个元素, 使用 stream() 时找到的是第一个元素;parallelStream() 并行时找到的是其中一个元素; findFirst() :找到第一个元素; 值得注意的是,这两个方法返回的是一个 Optional 对象,它是一个容器类,能代表一个值存在或不存在
private static void terminalOperation() {
int[] array = new int[]{
1, 2, 3, 4, 5, 2, 1, 3, 7
};
OptionalInt res = Arrays.stream(array).reduce(Integer::sum);
int res1 = Arrays.stream(array).reduce(0, Integer::sum);
List<Widget> widgetList = Widget.genRandomWidgets(10);
int sumOfWeights = widgetList.stream().reduce(0, (sum, b) -> sum + b.getWeight(), Integer::sum);
System.out.println("res = " + res + " res1 = " + res1 + " sumOfWeights = " + sumOfWeights);
ArrayList<String> strings = Arrays.stream(array).collect(ArrayList::new, (c, e) -> c.add(e + ""), ArrayList::addAll);
System.out.println(strings);
List<String> weights = widgetList.stream().map(t -> t.getWeight() + "").collect(Collectors.toList());
System.out.println(weights);
OptionalInt min = Arrays.stream(array).min();
OptionalInt max = Arrays.stream(array).max();
long count = Arrays.stream(array).count();
System.out.println("min = " + min + " max = " + max + " count = " + count);
boolean anyMatch = Arrays.stream(array).anyMatch(t -> t > 5);
boolean allMatch = Arrays.stream(array).allMatch(t -> t > 5);
boolean noneMatch = Arrays.stream(array).noneMatch(t -> t > 5);
System.out.println("anyMatch = " + anyMatch + " allMatch = " + allMatch + " noneMatch = " + noneMatch);
OptionalInt findAny = Arrays.stream(array).parallel().findAny();
OptionalInt findFirst = Arrays.stream(array).findFirst();
System.out.println("findAny = " + findAny + " findFirst = " + findFirst);
}
参考文献
Stream
|