筛选和切片
用谓词筛选
filter
使用Stream接口中的filter方法
筛选有所的素菜
List<Dish> vegetairanMenu = menu.stream()
.filter(Dish::isVegetarian)
.collect(Collectors.toList());
谓词筛选一个流.png
distinct
筛选各异的元素
Stream的distinct方法,它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流,通俗的说就是不去除重复元素
List<Integer> number = Arrays.asList(1,2,1,3,3,2,4);
number.stream()
.filter(integer -> integer%2==0)
.distinct()
.forEach(System.out::println);
image.png
limit
截断流
limit(n),返回一个不超过给定长度的流
热量超过300卡路里的头三道菜
List<Dish> dishes = menu.stream()
.filter(dish -> dish.getCalories() > 300)
.limit(3)
.collect(Collectors.toList());
注意该方法只选出了复合谓词的头三个元素,就立刻返回结果
skip
skip(n) 返回丢掉了前n个元素的流。如果流中不足n个,则返回一个空流
跳过超过300卡路里的头两道菜,并返回剩下的
List<Dish> dishes = menu.stream()
.filter(dish -> dish.getCalories() > 300)
.skip(2)
.collect(Collectors.toList());
映射
map
对流中每一个元素应用函数
提取流中菜肴的名称
List<String> dishes = menu.stream()
.map(Dish::getName)
.collect(Collectors.toList());
给定一个单词列表,返回另一个列表,显示有几个字母
List<String> words = Arrays.asList("Java 8","Lambda","In","Action");
List<Integer> wordLengths =words.stream()
.map(String::length)
.collect(Collectors.toList());
找出每到菜名有多长
List<Integer> dishes = menu.stream()
.map(Dish::getName)
.map(String::length)
.collect(Collectors.toList());
flatmap
流的扁平化
一张词表,返回一张列表,列出里面个不相同的字符
这个使用map是不可以的,如下
words.stream()
.map(word -> word.split(""))
.distinct()
.collect(Collectors.toList());
把单词映射成一个字符表,然后去重,map方法的lambda表达式为每个单词返回一个String[]。因此map返回的流实际上是Stream<String[]>类型,我们想要的事用Stream<String>类表示一个字符流,这时候要使用flatmap
1,尝试使用map和Arrays.stream()
我们需要一个字符流,而不是数组流,Arrays.stream()的方法可以接受一个数组并产生一个流,还是不行因为我们得到的是一个独立的流
2,使用flatmap
List<String> words = Arrays.asList("Java 8", "Lambda", "In", "Action");
List<String> uniqueCharacters = words.stream()
.map(word -> word.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
使用flatMap找出单词列表中各不相同的字符.pngflatMap方法效果,个数组不是分别映射成一个流,而是映射成流内容,所有使用map(Arrays::stream)时生成的单个流都被合并起来,即扁平化为一个流
map主要是用于遍历每个参数,然后进行参数合并或者返回新类型的集合。
flatMap主要是用于流合并,流转换,这个功能非常实用,他是默认实现多CPU并行执行的,所以我们合并集合优先实用这种方式。
查找和匹配
anyMatch
流中是否有一个已结元素能匹配给定的谓词
if (menu.stream().anyMatch(Dish::isVegetarian)){
}
会返回一个boolean值,因此是一个终端操作
allMatch
流中元素是否都能匹配给订的谓词
boolean isHealthy = menu.stream().allMatch(dish -> dish.getCalories() < 1000);
noneMatch
确保流中没有任何元素与给定谓词匹配
boolean isHealthy = menu.stream().noneMatch(dish -> dish.getCalories() >= 1000);
短路求值
比如and操作只要检测到一个为false就不需要检测后面的表达式了,对于流而言allMatch,anyMacth,noneMatch,findFiirst,findAny
查找元素
findAny
返回当前流中的任意元素
找出一到素食菜肴
Optional<Dish> dish = menu.stream()
.filter(Dish::isVegetarian)
.findAny();
Optional
是一个容器,代表一个值存在或者不存在
isPresent() 有值返回true,否则返回false
ifPresent(Consumer<T>) 值存在是执行给定的代码块
T get() 会在值存在是范湖值,否则抛出NoSuchElement异常
T orElse(T other) 会在值不存在时返回值,否则返回默认值
检测Optional对象中是否存在一道菜可以访问其名称
menu.stream()
.filter(Dish::isVegetarian)
.findAny()
.ifPresent(dish -> System.out.println(dish.getName()));
findFirst
查找流中第一个元素
Optional<Dish> dish = menu.stream()
.filter(Dish::isVegetarian)
.findFirst();
为什么会同时有findFirst findAny?
因为并行,findFirst在并行上限制很多,如果不关心返回的数据是哪个那么使用findAny
规约
reduce
元素求和
int sum = 0;
for (int x:first){
sum = +x;
}
使用流
int sum2 = first.stream().reduce(0,(a,b) -> a + b);
使用reduce来对流中的数字求和.png
首先0作为lambda(a)的第一个参数,从流中获取4作为第二个参数。0+4=4,生成新的累计值,累计值在和下一个5调用lambda,依次类推
也可以简写成
int sum3 = first.stream().reduce(0,Integer::sum);
无初始值
Optional<Integer> sum4 = first.stream().reduce(Integer::sum);
最大值和最小值
Optional<Integer> min = first.stream().reduce(Integer::min);
数值流
int calories = menu.stream()
.map(Dish::getCalories)
.reduce(0,Integer::sum);
这段代码的问题是,暗含装箱操作,每一个Integer都必须拆箱成一个原始类型,在进行求和
原始类型流特化
映射到数值流
IntStream,DoubleStream,LongStream
int calories = menu.stream()
.mapToInt(Dish::getCalories)
.sum();
使用mapToInt,mapToDouble,mapToLong,如果流失空返回为0
转换回对象流
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();
OptionalInt,OptionalLong,OptionalDouble
找到IntStream中的最大值,如果没有则为1
OptionalInt maxCalories = menu.stream().mapToInt(Dish::getCalories).max();
int max = maxCalories.orElse(1);
数值范围
IntStream,LongStream静态方法用用于生成范围值range,rangeClosed
IntStream evenNumbers = IntStream.rangeClosed(1,100);
构建流
由值创建流
Stream<String> stringStream = Stream.of("java 8 ","lambda","in","action");
由数组创建流
IntStream intStream = Arrays.stream(nums);
由文件生成流
long uniqueWords = 0;
try (Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())) {
uniqueWords = lines.flatMap(l -> Arrays.stream(l.split("")))
.distinct()
.count();
} catch (IOException io) {
}
由函数生成流
Stream.iterate Stream.generate创建无限流
生成10和偶数
Stream.iterate(0,n -> n + 2)
.limit(10)
.forEach(System.out::println);
Stream.generate(Math::random)
.limit(10)
.forEach(System.out::println);
他们两个的区别是iterate依赖每次新生成的值,generate不依赖新生成的值
无限流不能做排序和归约
网友评论