Java中的Stream流API

简介

流机制用于快速的对于数据进行处理,我们可以使用它和lambda表达式达到一个简洁的数据处理;
对于数据的处理,使用流可以避免再使用其他的加工步骤,更关注于结果的具体表现,而非如何去实现流程;比如:如果想要对于一个0-100整形数组nums,进行大于50的计数操作;

public static void main(String[] args) {
    
    
        int[] nums = new int[10];
        for (int i = 0; i < nums.length; i++) {
    
    
            nums[i] = new Random().nextInt(100);
        }
        //不适用流的遍历方式
        long count = 0L;
        for (int i = 0; i < nums.length; i++) {
    
    
            if(nums[i]>50){
    
    
                count++;
            }
        }
        //使用流
        long count2 = Arrays.stream(nums).filter(n -> n > 50).count();
        System.out.println(count==count2);
    }

通过这种方式可以直接通过方法名来说明流程想法,fiflter筛选,count计数;而不去考虑具体实现过程;此外也可以使用并行流加快操作;
long count = Arrays.parallelStream.filter(n -> n > 50).count;

流的特性:
1、流不存储数据,数据存储在底层的集合或按需生成;
2、流的操作不会修改数据源,即使是操作每一数据进行操作,源数据不会改变,但是依然应尽量避免使用流之后再修改源数据集;
3、流的操作是惰性的,走一步算一步,可在任何地方停止;

1、流的创建

//静态方法创建
Stream<String> stream1 = Stream.of("a","b","cs");
//创建空流;
Stream<String> stream2 = Stream.empty();
//创建无限流
//只包含aa的流
Stream<String> stream3 = Stream.generate(() -> "aa");
//包含随机数的无限流
Stream<Double> stream4 = Stream.generate(Math::random);
//创建一个0,1,2,3的有序序列无线流;
Stream<Integer> stream5 = Stream.iterate(0,n->n=n+1);
//通过加一个参数创建一个0,1,2,3的有序序列有限流;
Stream<Integer> stream6 = Stream.iterate(0, n->n<10, n->n=n+1);
/*
*创建流的方式还有很多,比如Arrays和Collections都提供有stream方法,此外Files,Scanner等都有提供流;
*/

2、过滤创建新流和截出子流

使用映射关系返回新流
fllter() 用于流中取出符合条件的流并取出
map() 用于对于输入的流每一个元素进行操作映射出一个新流返回;
flatMap()用于在一个完整流所有元素完成映射后再返回结果;

        Stream<Integer> stream = Stream.of(null,0,1,2,3,4,null);
        stream.filter(Objects::nonNull)
                //  如果一个方法返回的是流,flarMap可以将返回的流合并起来;
                .flatMap(n-> Stream.iterate(0, m -> m < n, m -> m + 1))
                .forEach(System.out::println);//0 01 012 0123,如果使用map会返回多个流的形式;而非一个流;

几个常用的方法;
limit(long n);用于截断前n个元素并返回子流;
skip(long n);用于摒除前n个元素返回子流;
takeWhile(Predicate predicate);主要用于拿到满足条件的流;
dropWhile(Predicate predicate);主要用于拿到不满足条件的流;
concat(Stream a,Stream b:用于合并a,b流变为交替形式;

3、操作流(中间操作)

distinct() :对流中的元素去重
sorted() :对流中所有数据排序
peek(),主要是利用流中数据进行某项操作,比如打印;常用于调试;

Stream<Integer> stream = Stream.of(null, 0, 1, 2, 3, 4, 5, null);
        stream.filter(Objects::nonNull)
                .peek(n ->{
    
    
                    n=n+2;
                    System.out.println(n  + "  peek结束");})
                .forEach(System.out::println);
        /*
        2  peek结束
        0
        3  peek结束
        1
        4  peek结束
        2
        5  peek结束
        3
        6  peek结束
        4
        7  peek结束
        5
         */

4、使用流中数据(终结操作)

终结操作主要用于在流中获取数据,我们可以通过上述的创建流和转换流或者中间操作,获得想要的流,最终取出数据作为中间操作;
max/min两个方法用于取大小值;
iterator():获取迭代器;
foreach():遍历对每个元素进行操作;如果是并行流且需要顺序,则使用foreachOrdered方法;
collect(),将流中的元素收集到集合中,需要传入collector接口实例;
Collectors:收集器工具类,实现各种有用的归约操作的Collector实现,例如将元素累积到集合中,根据各种标准汇总元素等。使用这个工具类更方便的创建收集器实例;其中也有不少的工具类,如getMax,getCount,getAverage等;

List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,1,2,3,5,4));
        List<Integer> collect = list.stream().map(n -> n * 10).distinct().sorted()
                .collect(Collectors.toList());

        System.out.println(collect.toString());//[10, 20, 30, 40, 50]

映射表:如果需要对于流中的元素建立映射关系,可以通过Collectors.toMap()方法进行操作;注意这里的映射方法中,存入map的key不可以重复;如果重复会有异常;

 List<Integer> nums2 = new ArrayList<>(Arrays.asList(1, 2, 3, 4,3,5));
        int[] key = new int[1];
        Map<String, Integer> collect2 = nums2.stream()
                .collect(Collectors.toMap((n) -> {
    
    
                    key[0]++;
                    return "第" + key[0] + "元素加一后的值";
                }, (n) -> n + 1));
        System.out.println(collect2.toString());//{第6元素加一后的值=6, 第2元素加一后的值=3, 第3元素加一后的值=4, 第1元素加一后的值=2, 第4元素加一后的值=5, 第5元素加一后的值=4}

对于收集器还有更多的方法,比如groupingBy的分组方法,依据某各方法进行分组;

Guess you like

Origin blog.csdn.net/qq_44830792/article/details/121118513