流
-
使用流,只需要说明想做什么,声明式编程,说明要做什么而不说明如何完成
//选择再 5-20 之间从小到大不同的 7 个随机数 new Random(47) .ints(5, 20) .distinct() .limit(7) .sorted() .forEach(System.out:: println);
-
流的列表是一个“延迟列表”(延迟求值),可以表示非常大的序列而不需要考虑内存的问题
import java.util.stream.*
- 流类型
Stream<>
创建流¶
- 从一组条目创建
Stream.of(a,b,c...).
- 从Collection创建
Collection.stream().
-
Map要先
.entrySet()
生成每个对象包含一个键与其关联的值 -
随机数流
Random rand = new Random(47); rand.ints()//无参数无限流 rand.ints(n)//一个参数表示流的大小 rand.ints(down, up)//两个参数表示上下边界 rand.ints(n, down, up )
- 只可以生成int、long、double
-
使用[.boxed()]打包为包装类型
-
range(from, to)
- 生成 int 流[from, to)可以用于循环
-
for(int i:range(10,20).toArray())
-
generate()
- 用于产生由完全相同的对象组成的流
- 需要将一个生成对象的lambda表达式传入
Stream.generate(()->"duplicate")...
- 创建一个由重复字符串组成的流
-
也可以传入一个方法引用
-
iterate()
- 从一个参数开始,将其传递给第二个参数引用的方法,结果添加到流并作为下一次调用的第一个参数
-
生成斐波那契序列
public class Fibonacci { int x = 1; Stream <Integer> numbers() { return Stream.iterate(0, i -> { int result = x + i; x = i; return result; }); } }
-
流生成器
- 创建一个生成器对象用于生成
- 创建
Stream.Builder<String> builder = Stream.builder();
- 使用
.add()
向生成起添加元素 -
构建
builder.build()
构建之前可以随意添加元素- 直接使用build后的结果就可以获取流
-
Arrays
- 将数组转化为流
Arrays.stream(arrp[],[from, end])
- 可以只是选择的范围
-
对于基本类型会产生IntStream、LongStream、DoubleStream
-
使用正则表达式切割字符串得到字符串流
import java.util.regex.Pattern
Pattern.compile("正则").splitAsStream(String);
- 创建空流
-
Stream<String? s = Stream.empty();
-
使用迭代器从流获取元素
Stream <Integer> stream = new Random().ints(0, 100).boxed().distinct(); Iterator <Integer> iterator = stream.iterator();
- 通过操作迭代器进行访问
修改流元素¶
skip(n)
丢弃前n个元素- 查看流对象
peek(System.out::print)
-
要求输入Consumer函数式接口,即没有返回值,也就不会对流修改
-
sorted([比较函数])
- 内置比较如
Comparator.reverseOrder()
-
使用lambda(创建匿名类)
List <Person> sortedByAge = people.stream() .sorted((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge())) .collect(Collectors.toList());
-
移除重复元素
distinct()
filter()
过滤元素-
过滤操作只保留传给过滤函数后返回值为true的元素
public static boolean isPrime(long n){ return rangeClosed(2,(long)Math.sqrt(n)) .noneMath(i-> n%i==0);//有一项不满足就终止并返回 false } //生成素数 public LongStream numbers(){ return iterate(2, i-> i+1) .filter(Prime:: isPrime); }
-
map(Function)
- 输入流中的对象,结果作为输出流继续传递
-
mapToInt(TOintFunction)
等基本类型map -
组合流
- 如果在map函数中生成的是流,那我们得到了一个有流组成的嵌套流
flatMap(Function)
接受生成流的函数,并对生成的流进行扁平化展开为元素flatMapToInt(Function)
用于处理基础类型
-
concat()
用于组合两个流 -
从文件创建
- 按照单词创建流
public class FileToWords { public static Stream <String> stream(String filePath) throws Exception { return Files.lines(Paths.get(filePath)) .skip(1) // First (comment) line .flatMap(line -> Pattern.compile("\\W+").splitAsStream(line)); // 将对行拆分的字符串流扁平化 } }
Optional类型¶
Optional
是一个容器对象,它可能包含一个值,也可能不包含。使用Optional
可以更优雅地处理可能为空的情况- 不只可以用于流,也可以在任何涉及null的地方使用,以减少异常,方便对null进行处理
- 某些标准流操作会返回Optional对象
- 流操作经常以
Optional
结束 findFirst()
返回包含第一个元素的Optional,如果流为空则返回Optional.empty
findAny()
返回包含任何元素的Optionalmax() min()
-
数值化流(IntStream)的
average()
-
流聚合
reduce([T identity可选初始值], BinaryOperator<T> accumulator);
- 对所有元素进行操作合并,得到聚合后的汇总结果
-
reduce(0, (a, b) -> a + b);
获取元素的总和 -
便捷函数:对Optional中的数据进行快捷操作(定义在null时进行的操作)
ifPresent(Consumer)
如果值存在就用值来调用Consumer(一个参数没有返回值)orElse(otherObject)
如果对象存在则返回对象否则返回otherObjectorElseGet(Supplier)
不存在则执行一个Supplier
函数并返回其结果。-
orElseThrow(Supplier)
不存在则抛出由函数创建的异常//为 null 则怕抛出异常 title = Optional.ofNullable(newTitle) .orElseThrow(EmptyTitleException:: new); //为 null 则自动创建新对象 person = Optional.ofNullable(newPerson) .orElse(new Person());
-
创建Optional
- 静态方法
Optional.empty()
返回空Optionalof(value)
要求value不是null-
ofNullable(vlaue)
允许为null,会自动返回Optional.empty
-
Optional上的操作
-
修改
filter(Predicate)
将函数用于Optional的内容并返回结果(返回false则转化为empty),如果Optional和函数不匹配就转化为empty(而不是直接删除)(本身就是empty则直接返回)map(Function)
应用Function对非empty元素进行转化flatMap(Function)
由提供的Function把结果包装在Optional中,flatMap不会再做任何包装(需要在Function中创建Optional)
-
Optional流
- 创建
stream.map(signal -> Optional.ofNullable(signal))
- 获得Optional中的对象
stream .filter(Optional:: isPresent)//保留非 empty .map(Optional:: get)获取对象 ...
消费流元素¶
- 接受一个流并生成最终结果,通常作为最后一件事
- 将流转化为数组
-
toArray()
自动转换到恰当类型的数组 -
对每个流元素进行操作
forEach(Consumer)
如输入System.out::println
- 使用多处理器
parallel()
时顺序是不确定的
- 使用多处理器
-
forEachOrdered(Consumer)
确保按照原始流顺序进行 -
收集
collect(Collector)
将元素累加到一个结果集合-
指定生成的集合类型
collect(Collectors.toCollection(TreeSet::new))
public class TreeSetOfWords { public static void main(String [] args) throws Exception { Set <String> words2 = Files.lines(Paths.get("TreeSetOfWords.java")) //根据非单词字符划分 .flatMap(s -> Arrays.stream(s.split("\\W+"))) //去除非数字 .filter(s -> ! s.matches("\\d+")) // No numbers //去除左右空白 .map(String:: trim) //去除太短 .filter(s -> s.length() > 2) .limit(100) //指定生成的集合类型 .collect(Collectors.toCollection(TreeSet:: new)); System.out.println(words2); } }
-
转化为map
Collectors.toMap(获取key的函数,获取val的函数)
- 大部分时候都可以直接使用预定义的Collector
collect(Supplier, BiConsumer, BiConsumer)
创建新集合,将下一个元素包含到结果中,将两个值组合起来-
collector(ArrayList::new,ArrayList::add,ArrayList::addAll)
-
组合
-
reduce([identity(组合的初始值),] BinaryOperator)
组合所有流元素,返回Optional -
匹配
allMatch(Predicate)
每一个元素都是true才返回trueanyMatch(Predicate)
任何一个为true就返回truenoneMatch(Predicate)
没有true-
都是短路计算
-
选择
findFirst()
findAny()
对于非并行的流也是返回第一个-
获取最后一个元素
reduce((n1,n2)->n2)
-
获取信息
count()
元素数目max(Comparator)
- 许多类型有预定义的比较器,如
String.CASE_INSENSITIVE_ORDER
- 数值化流不需要比较器
- 许多类型有预定义的比较器,如
min(Comparator)
- 数值化流
average()
sum()
summaryStatistics()
获取摘要数据 (用于查看数值流的状态)