java8 in action:第五章学习使用流(Stream)的基本方式,勾股数与斐波拉契元祖序列实现

从上一次的学习中,流的学习中,我们知道了流的筛选,如filter。
这里将学习流的几个其他的方法的情况。

筛选各异的元素distinct###

List numbers=Arrays.asList(1,5,8,10,13);
    numbers.stream().filter(i-> i%2 ==0)
                    .distinct()
                    .forEach(System.out::println);

截断流limit###

List vegetarianMenu=menu.stream()
                              .filter(Dish::isVegetarian)
                              .limit(2)
                              .collect(toList());

跳过元素skip###

 List names=menu.stream()
              .filter(d -> d.getCalories()>350)
              .skip(2)
              .map(Dish::getName)
              .collect(toList());

中间流的使用是map映射用法###

要查出卡路里大于350的前两种食物的名字的长度。

List 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 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:
 Stream map(Function mapper);
Returns a stream consisting of the results of applying 
the given function to the elements of this stream.

flatMap:
 Stream flatMap(Function> 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 num1=Arrays.asList(1,2,3);
List 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 findVegetarianDish() {
    return menu.stream().filter(Dish::isVegetarian).findAny();
}

Optional dish=findVegetarianDish();
dish.ifPresent(d -> System.out.println(d.getName()));

查询需要将流中所有元素结合起来得到一个值成为归约操作。
求和:

    List 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 min=numbers.stream().reduce(Integer::min);
min.ifPresent(System.out::println);
Optional 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 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 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 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 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 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);

好了,今天就是这样了。

你可能感兴趣的:(java8 in action:第五章学习使用流(Stream)的基本方式,勾股数与斐波拉契元祖序列实现)