从上一次的学习中,流的学习中,我们知道了流的筛选,如filter。
这里将学习流的几个其他的方法的情况。
筛选各异的元素distinct###
List<Integer> numbers=Arrays.asList(1,5,8,10,13);
numbers.stream().filter(i-> i%2 ==0)
.distinct()
.forEach(System.out::println);
截断流limit###
List<Dish> vegetarianMenu=menu.stream()
.filter(Dish::isVegetarian)
.limit(2)
.collect(toList());
跳过元素skip###
List<String> names=menu.stream()
.filter(d -> d.getCalories()>350)
.skip(2)
.map(Dish::getName)
.collect(toList());
中间流的使用是map映射用法###
要查出卡路里大于350的前两种食物的名字的长度。
List<Integer> namesLength=menu.stream()
.filter(d -> d.getCalories()>350)
.limit(2)
.map(Dish::getName)
.map(String::length)
.collect(toList());
流的扁平化,比如分解单词###
将java8 in action 三个词去掉重复的a,i,输出java8incto
需要flatMap
List<String> words=Arrays.asList("java8","in","action");
words.stream()
.map(word -> word.split(""))
.flatMap(Arrays::stream)//将各个生成流转换为由字母构成的数组
.distinct()
.collect(toList())
//.forEach(System.out::println);
.forEach(str -> System.out.print(str+"\t"));
通过源码简单比较map和flatMap
map:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
Returns a stream consisting of the results of applying
the given function to the elements of this stream.
flatMap:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
Returns a stream consisting of the results of replacing each element of
this stream with the contents of a mapped stream produced by applying
the provided mapping function to each element.
关键字: replacing each element of this stream。区别还是很明显的。
由列表[1,2,3]和[3,4]返回(1,3)(1,4)(2,3)(2,4)(3,3)(3,4)。
List<Integer> num1=Arrays.asList(1,2,3);
List<Integer> num2=Arrays.asList(3,4);
num1.stream()
.flatMap(i-> num2.stream().map(j -> new int[]{i,j}))
.collect(toList())
.forEach(num-> System.out.print("("+num[0]+","+num[1]+")"));
注意num其实是返回的一个对象,比如(1,3)。
改进需求,返回总和被3整除的对象。
num1.stream()
.flatMap(i-> num2.stream()
.filter(j-> (i+j)%3==0)
.map(j -> new int[]{i,j}))
.collect(toList())
.forEach(num-> System.out.print("("+num[0]+","+num[1]+")"));
查找和匹配###
anyMatch:检查谓词是否至少匹配一个
allMatch:检查谓词是否匹配所有元素
noneMatch:与allMatch相对的。没有任何元素和给定的谓词匹配
if(num1.stream().anyMatch(num -> num%3==0)){
System.out.println("存在被3整除的!");
}
findAny:返回当前流的任意元素
一般只能写成这样:
num1.stream().filter(num -> num>1)
.findAny();
看不到效果,需要结合Optional。
private static Optional<Dish> findVegetarianDish() {
return menu.stream().filter(Dish::isVegetarian).findAny();
}
Optional<Dish> dish=findVegetarianDish();
dish.ifPresent(d -> System.out.println(d.getName()));
查询需要将流中所有元素结合起来得到一个值成为归约操作。
求和:
List<Integer> numbers=Arrays.asList(1,2,3,4,5);
int num=numbers.stream().reduce(0,(a,b) -> a+b);
System.out.println(num);
int num2=numbers.stream().reduce(0,Integer::sum);//调用Integer自带的sum方法
System.out.println(num2);
求最值:
Optional<Integer> min=numbers.stream().reduce(Integer::min);
min.ifPresent(System.out::println);
Optional<Integer> max=numbers.stream().reduce(Integer::max);
max.ifPresent(System.out::println);
装箱成本
int calories=menu.stream()
.map(Dish::getCalories)
.reduce(0, Integer::sum);
代码中将Integer转成int,都要去拆箱。改进办法mapToInt,mapToDouble,mapToLong。
int calories2=menu.stream()
.mapToInt(Dish::getCalories)
//.reduce(0, Integer::sum);
.sum();//sum默认返回0
将数值转为stream。
IntStream calories3=menu.stream()
.mapToInt(Dish::getCalories);
Stream<Integer> intToStream=calories3.boxed();
找最值。
OptionalInt maxCalories=menu.stream()
.mapToInt(Dish::getCalories)
.max();
int max=maxCalories.orElse(10);//如果没有最大值,给10
range pk rangeClosed,直接上demo看区别:
IntStream evenNumbers=IntStream.rangeClosed(1, 100);
System.out.println(evenNumbers.count());//100
IntStream evenNumbers2=IntStream.range(1, 100);
System.out.println(evenNumbers2.count());//99
range不包括结束值。
求100以内的勾股数:
Stream<int[]> gain=IntStream.rangeClosed(1, 100).boxed()
.flatMap(a -> IntStream.range(a, 100)
.filter(b -> Math.sqrt(a*a +b*b)%1==0)//判断斜边是否为整数
.mapToObj(b -> new int[]{a,b,(int) Math.sqrt(a*a+b*b)})
.filter(t -> t[1]<101&&t[2]<101)
);
gain.forEach(t -> System.out.println(t[0]+","+t[1]+","+t[2]));
换一种方式实现:
Stream<double []> gain2=IntStream.rangeClosed(1, 100).boxed()
.flatMap(a -> IntStream.rangeClosed(a, 100)
.mapToObj(b -> new double[]{a,b,Math.sqrt(a*a+b*b)})
.filter(t -> t[2] %1==0&&t[1]<101&&t[2]<101)
);
gain2.forEach(t -> System.out.println(t[0]+","+t[1]+","+t[2]));
创建流的方式:
值创建:
Stream<String> stream=Stream.of("java8","in","action");
stream.map(String ::toUpperCase).forEach(System.out::println);
数组创建:
int [] numbers={3,5,3,7,23};
int sum=Arrays.stream(numbers).sum();
文件生成流:
long words=0;
try(Stream<String> lines=Files.lines(Paths.get("F:\\Java world\\data.txt"),Charset.defaultCharset())){
words=lines.flatMap(line -> Arrays.stream(line.split("")))
.distinct()
.count();
System.out.println(words);
}
catch (Exception e) {
e.printStackTrace();
}
迭代:斐波拉契元祖序列实现###
Stream.iterate(new int[]{0,1}, t -> new int[]{t[1],t[0]+t[1]})
.limit(20)
.map(t -> t[1])
.forEach(System.out::println);
好了,今天就是这样了。