zoukankan      html  css  js  c++  java
  • java8-流的操作

    流的操作

    流的使用一般包括三件事:

    一个数据源来执行一个查询;

    一个中间操作链,形成一条流的流水线;

    一个终端操作,执行流水线,并能生成结果

    中间操作

    操作 类型 返回类型 操作参数 函数描述符
    filter 中间 Stream Predicate T -> boolean
    map 中间 Stream Function<T,R> T->R
    limit 中间 Stream
    sorted 中间 Stream Comparator (T,T)->int
    distinct 中间 Stream

    终端操作

    操作 类型 目的
    forEach 终端 消费流中的每个元素并对其应用Lambda.这一操作返回void
    count 终端 返回流中元素的个数,这一操作返回long
    collect 终端 把流归约成一个集合,比如List,Map甚至是Integer

    使用流

    筛选

    出了filter ,流还支持一个叫做distinct的方法,它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流.例如,如下代码会筛选出列表中所有的偶数,并确保没有重复

    List<Integer> numbers = Arrays.asList(1,2,1,3,3,2,4);
    numbers.stream()
      .filter(i -> i%2 ==0)
      .distinct()
      .forEach(System.out::println);
    

    截断流

    流支持limit(n) 方法,该方法会返回一个不超过给定长度的流.

    List<Dish> dishes = menu.stream()
    .filter(d->d.getCalories()>300)
    .limit(3)
    .collect(toList());
    

    跳过元素

    流还支持skip(n)方法,返回一个扔掉了前n个元素的流.

    List<Dish> dishes = menu.stream().filter(d->d.getCalories()>300).skip(2).collect(toList());
    

    映射

    对流中每一个元素应用函数

    例如: 如果要找出每道菜的名称有多长,则如下:

    List<Integer> dishNameLengths = menu.stream().map(Dish::getname).map(String::length).collect(toList())
    

    流的扁平化

    例如:给定单词列表["hello","world"],你想要返回列表["h","e","l","l","o","w","o","r","l","d"]

    利用上面的可能是:

    words.stream().map(word->word.split("")).distinct().collect(toList());
    

    这个方法的问题自傲与,传递给map方法的Lambda为每个单词返回一个String[] (String列表),因此,map返回的流实际上是Stream< String[] >类型的.你真正想要的是用Stream< String > 来表示一个字符流

    1.尝试使用map和Arrays.stream()

    String[] arrayOfWords = {"GoodBye","World"};
    Stream< String> streamOfWords = Arrays.stream(arrayOfWords);	
    

    2.使用flatMap

            String[] arrayOfWords = {"GoodBye","World"};
            Stream< String> streamOfWords = Arrays.stream(arrayOfWords);
            List<String[]> collect = streamOfWords.map(m -> m.split("")).collect(toList());
            System.out.println(collect);
    

    例2:

    给定列表[1,2,3] 和[3,4] ,返回[(1,3),(1,4),(2,3).....]

            List<Integer> integers = Arrays.asList(1, 2, 3);
            List<Integer> integers1 = Arrays.asList(3, 4);
            List<int[]> collect = integers.stream()
                    .flatMap(i -> integers1.stream()
                            .map(j -> new int[]{i, j}))
                    .collect(toList());
            collect.forEach(i -> {
                String s = Arrays.toString(i);
                System.out.println(s);
            });
    

    例3:

    扩展前面的例子,只返回综合能被3正处的数对呢?

            List<Integer> int1 = Arrays.asList(1, 2, 3);
            List<Integer> int2 = Arrays.asList(3, 4);
            List<int[]> collect = int1.stream().flatMap(i -> int2.stream().filter(j -> (i + j) % 3 == 0).map(j -> new int[]{i, j})).collect(toList());
            System.out.println(collect);
    

    查找和匹配

    匹配
    1.检查谓词是否至少匹配一个一元素

    anyMatch方法可以回答"流中是否有一个元素能匹配给定的谓词"

    if(menu.stream().anyMatch(Dish::isVegetarian)){
      	System.out.println("The menu is vegetarian friendly!!");	
    }
    
    2.检查谓词是否匹配所有元素

    例如:用allMatch来看看菜品是否有利健康

    boolean isHealthy = menu.stream().allMatch(d->d.getCalories()<1000);
    
    3.确保流中没有任何元素与给定的谓词匹配 noneMatch
    boolean isHealthy = menu.stream().noneMatch(d->d.getCalories()<1000);
    
    查找
    findAny方法将返回当前流中的任意元素
    Optional<Dish> dish = menu.stream().filter(Dish::isVegetarian).findAny();
    
    查找第一个元素
    List<Integer> someNumbers = Arrays.asList(1,2,3,4,5);
    Optional<Integer> firstSquareDivisibleByThree = 
    	someNumbers.stream()
    	.map(x->x*x)
    	.filter(x->x%3 == 0)
    	.findFirst();
    

    归约

    元素求和 reduce

    reduce接受两个参数

    一个初始值,这里是0

    一个BinaryOperator< T >来将两个元素结合起来产生一个新值 ,这里我们用的是lambda(a,b)->a+b;

    int sum = numbers.stream().reduce(0,(a,b)->a+b);
    

    相乘:

    int product = numbers.stream().reduce(1,(a,b)->a*b);
    

    在java 8 中,Integer类现有了一个静态的sum方法来对两个数求和

    int num=numbers.stream().reduce(0,Integer::sum);
    

    最大值:

    Optional<Integer> max = numbers.stream().reduce(Intger::max)
    

    最小值:

    Optional<Integer> min = numbers.stream().reduce(Integer::min);
    

    数值流

    原始类型流特化

    java 8 引入了三个原始类型特化流接口来专门支持处理数值流的方法:IntStream . DoubleStream 和LongStream,.

    分别将流中的元素特化成为int,long ,double,从而避免了暗含装箱成本

    1.映射到数值流

    将流转化为特化版本的常用方法是mapToInt,mapToDouble ,mapToLong.

    int calaories = menu.stream()
    	.mapToInt(Dish::getCalories)//返回一个IntStream
    	.sum();
    

    2.转换回対向流 boxed

    IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
    Stream<Integer> stream = intStream.boxed();
    

    3.默认值OptionalInt

    IntStream中有个默认值0,所以,为了解决求最大值或最小值的问题 ,使用Optional原始类型特化版本:OptionalInt,

    OptionalDouble,OptionalLong.

    例如:要找到IntStream中的最大元素,可以调用max方法,它会返回一个OptionalInt:

    OptionalInt maxCalories = menu.stream()
    	.mapToInt(Dish::getCalories)
    	.max();
    //如果没有最大值的话,可默认一个最大值
    int max = maxCalories.orElse(1);
    

    4.数值范围

    假如你想要生成1到100之间的所有数字. java8引入了两个可以用于IntStream和LongStream的静态方法,帮助生成这种范围:range和rangeClosed. 这两个方法都是第一个参数接受起始值,第二个参数接受结束值.但是range是不包含结束值的,而rangeClosed则包含结束值

    IntStream evenNumbers = IntStream.rangeClosed(1,100)
    	.filter(n -> n % 2 == 0);//一个从1到100的偶数流
    
    System.out.println(evenNumbers.count());//从1到100有50个偶数
    

    构建流

    由值创建流

    可以使用静态方法Stream.of,通过显示值创建一个流.它可以接受任意数量的参数

    Strean<String> stream = Stream.of("java 8","Lambdas ","In ","Action");
    stream.map(String::toUpperCase).forEach(System.out::println);
    //使用empty得到一个空流
    Stream<String> emptySteam = Stream.empty();
    
    由数组创建流
    int[] numbers = {2,3,4,11,13};
    int sum = Arrays.stream(numbers).sum();
    
    由文件生成流
    long uniqueWords = 0;
    try(Stream<String> lines = 
    	Files.lines(Paths.get("data.txt"),Charset.defaultCharset())){
    	uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
    		.distinct()
    		.count();
    }catch(IOException e){
      
    }
    
    由函数生成流:创建无限流

    Stream.iterate和Stream.generate ,一般来说应该使用limit(n)来对这种流加以限制,以避免打印无穷多个值

    1.迭代

    Stream.iterate(0,n -> n+2)
    	.limit(10)
    	.forEach(System.out::println);
    

    2.生成

    与iterate方法类似,generate方法也可生成一个无限流.但generate不是依次对每个新生成的值应用函数的.它接受一个Supplier< T >类型的Lambda提供新的值

    Stream.generate(Math::random)
      .limit(5)
      .forEach(System.out::println);
    
    //下面的代码就是出安静了一个斐波那契
    IntSupplier fib = new IntSuppleir(){
     	private int previous = 0;
      	private int current = 1;
      	public int getAsint(){
          	int oldPrevious = this.previous;
          	int nextValue = this.previous + this.current;
          	this.previous = this.current;
          	this.current = nextValue;
          	return oldPrevious;
      	}
    };
    IntStream.generate(fib).limit(10).forEach(System.out::println);
    
  • 相关阅读:
    拷贝构造,移动构造,右值引用,左值,右值,std::move,std::forward,std::ref
    枚举类型 enum以及enum class
    C++ 静态库LIB的使用方法
    array(数组容器)
    C++标准模板库STL
    C++ 动态库DLL的使用方法
    函数指针与回调函数
    VS项目属性等一系列问题
    逻辑运算符(且或非),位运算符(异或),函数对象运算(bit_or)
    pinpoint-grpc编译异常问题记录
  • 原文地址:https://www.cnblogs.com/luozhiyun/p/7988521.html
Copyright © 2011-2022 走看看