常用的流的操作
java8流库新增的流遵循了 做什么而不是怎么做的原则
- 流不会修改其数据源
- 流不会储存元素
- 流的操作尽量会怠性执行
var str=new String(Files.readAllBytes(Paths.get("d://1.txt")),StandardCharsets.UTF_8);
List<String> list=List.of(str.split("\\PL+"));
long count=list.stream().filter(w->w.length()>10).count();
System.out.print(count+"\n"+list);
在如示代码中,stream会返回一个作用于 该列表的流,filter会返回一个只包含长度大于1
0 的元素的流。count方法将这个流的 元素计数
各种类创建Stream对象的方法 | 效果 |
---|---|
String类 stream() | 返回一个流 |
String类 parallelStream() | 返回一个并行的流 |
Files类 lines() | 返回一个包含 包含了文件中所有行的流 |
Arrays类 stream(数组) | 返回一个流 |
Stream类的方法 | 效果 |
---|---|
filter(Predicate实例) | 过滤,返回一个满足条件的流 |
count() | 返回当前流中的元素数量,这是一个终止操作 |
of(可变参数.......) | 返回一个由指定元素创建的流 |
empty() | 创建不包含任何元素的流 |
generate(Supplier接口对象) | 用于创建无限流 |
ofNullable(Path对象) | 用一个对象创建一个 流,仅包含一个元素 |
iterate(起始值,判断是否继续的对象,进行操作的对象) | 迭代产生元素,组成这个流,终止操作 |
filter(筛选条件Predicate) | 保留符合条件的元素组成的流 |
map(处理函数) | 会把这个指定函数依次处理流中的每一个元素,但是将一个元素处理后得到一个流,最后会得到一个包含流的流 |
flatMap(处理函数) | 同上,但将流铺开,最后只得到一个流 |
limit(int n) | 得到前n个元素的 流 |
skip(int n) | 跳过前n个元素的 流 |
takeWhile(predicate对象) | 判断为 |
dropWhile(predicate对象) | |
concat(流1,流2) | static方法,连接两个流 |
sorted() | 排序 |
distinct() | 去除重复的元素 |
peek(Consumer实例) | 取出一个元素 |
max(Comparator实例) | 返回最大值,由Optional包装 |
min(Comparator实例) | 返回最小值,由Optional包装 |
fideFirst() | 找到第一个,由Optional包装 |
fideAny() | 找到任意一个,由Optional包装 |
anyMatch(Predicate实例) | 查找是否有匹配的,返回boolean,还有allMatch,noneMatch |
forEach(Consumer实例) | 任意顺序遍历,终止操作 |
forEachOrdered() | 按顺序遍历,终止操作 |
toArray() | 返回Object 数组,终止操作 |
toArray(String[]::new) | 像这样传入new 构造方法,会返回一个String数组终止操作 |
collect(Collector实例) | 收集操作,返回对应收集器的类型的对象 |
reduce(二元函数) | 将每一个元素操作,如同v1 op v2 op v3 .......,由此可以实现累加累乘,最后把结果返回回来 |
reduce(起始值,二元函数) | 同上 |
Collectors类 | 效果 |
---|---|
toList() | 创建一个List收集器 |
toSet() | 创建一个Set收集器 |
toCollection(Suppliers实例) | 创建一个收集器,如传入TreeSet::new |
joining() | 创建一个字符串收集器,进行拼接 |
joining(分隔符) | 同上,指定拼接时的分隔符 |
toMap(Fuction key,Function value) | 创建Map收集器 |
toMap(Fuction key,Function value,key相同时要做的处理) | 创建Map收集器,并给出key重复时的解决方案 |
toMap(Fuction key,Function value,key相同时要做的处理,TreeSet::new) | 创建Map收集器,指定返回 TreeMap对象 |
partitioningBy(Predicate实例) | 根据返回的真假来分组 |
groupingBy(Fuction实例) | 根据Function返回的值,来将相同的元素编组。这最终会返回一个 Map<T,List>对象 |
groupingBy(Fuction实例,Collector对象) | 同上,但值不是列表,而是你指定的,可以用toSet(),指定值变为集合,这里把这种叫做下游收集器 |
counting() | 下游收集器,返回列表中元素的个数 |
summing(Fuction实例) | 下游收集器,将每个元素被这个函数加工后产生的值,求和 |
maxBy(Comparator对象)同minBy() | 下游收集器,返回最大或最小值 |
[Int][Double][Long] 的接口实例) | 返回[Int][Double][Long]SummaryStatistics对象 |
[Int][Double][Long]SummaryStatistics类 | 方法 |
---|---|
getCount() | 返回汇总后的元素个数 |
getAverage() | 返回平均 |
getMax() | 返回最大 |
getMin() | 。。。。。 |
Optional类 | 效果 |
---|---|
orElse(其他值) | 返回Optional里的值,如果为空就 返回指定的 值 |
orElseGet(Suppliers实例) | 返回Optional里的值,如果为空就 返回这个 实例产生的值 |
orElseThrow(Suppliers实例) | 返回Optional里的值,如果为空就 抛出这个 实例的结果 |
ifPresent(Consumer实例) | 如果 Optional值存在就执行,不存在就不执行 |
ifPresentOrElse(Consumer实例1,Consumer实例2) | 如果存在就执行实例1,不存在就执行实例2 |
isPresent() | 判断是否存在 |
of(元素) | 创建Optional对象 |
empty() | 创建Optional对象 |
ofNullable(元素) | 如果元素不为null就返回of()的结果,为null就返回empty()的结果 |
map(Fuction实例) | 返回一个Optional,里面的值是被map方法处理过的 |
flatMap(Function实例) | 同上,如果值不存在,就返回空的Optional |
get() | 得到值 |
Stream() | 返回流 |
基本类型流
以上方法我们都是把整数放 到Stream<Integer>中,这样很低效。因此流库中有专门 对应基础类型的流,
如IntStream(还可以存储short,char,byte,Boolean),LongStream,DoubleStream(可以存储float)。
IntStream.of(1,2,3,4)//
Arrays.stream(数组,from,to)//创建IntStream的几种方法
range(from,to) | 返回一个该区间步长为1的元素组成的IntSream,左闭右开 |
---|---|
rangeClosed(from,to) | 同上,但左右都闭 |
boxed() | 将基本类型流变为普通流 |
字符串.codePoints() 返回一个IntStream流对象 当你有一个流时,可以用mapToInt,mapToLong,mapToDouble方法 将其转化为基本类型流
基本类型流于普通流的主要差别:
- toArray()返回一个基本类型数组
- 产生的可选结果是 OptionalInt或OptionalLong或OptionalDouble,没有get方法,但有getAsInt,getAsLong,getAsDouble方法
- 具有min,max,average方法
并行流
流使得并行处理变得十分容易,这个过程几乎是自动的。
流的parallel()方法 将一个流转换为并行的流,并且只要在执行最终操作时,这个流是在并行状态,那么中间所有的操作都会被被转换为并行
int arr=new int[12];//统计长度小于12的单词的个数
"I am slh's baba".parallelStream().forEach(
s->{if(s.length()<12)arr[s]++;});
//这是非常糟糕的代码,因为是并行的,多个进程不断更新,访问这个
//数组,会导致错误
Map<Integer,Long> map= "I am slh's baba".parallelStream().filter(
s->s.length<12).collect(groupingBy(String::length,counting()));
//这是将其按长度分组后,统计每组的个数
并行的流的最安全的处理方法就是 调用其自己的函数,将操作交给流本身自己全部进行 线程
在流上调用unordered()方法声明我们对排序不感兴趣,加快速度
Collector 类的gropingByConcurrent()以并行的方式处理,结果是无序的
不要指望把所有流转换为并行流就能加快操作
- 并行会导致大量开销,只有面对非常大的数据才划算
- 只有底层数据源能划分为多个部分时,并行才有意义
- 面对海量的内存数据比网络访问数据更有效
在java9之前,对Files.lines方法返回的流进行并行化是没有意义的,因为不可分。
但现在,该方法用的是内存映射文件,就可以有效分割。
如果要并行化随机数,就不要用Rondom.ints,Rondom.Longs,Rondom.Doubles方法中获得的流为起点,要用SplittableRandom类来