蔡不菜和他的uU们

  • 首页
  • 新鲜出炉
  • 我的记录
  • 我的动态
  • 我和uU
  • 好用分享
  • 关于与留言
志合者,不以山海为远;道乖者,不以咫尺为近
  1. 首页
  2. 学习,学习
  3. 正文

Lambda应用—Stream

2022年1月10日 452人阅读 0人点赞 0条评论

         Stream 的使用是Lambda应用的一个常见的场景,流的引入使得我们可以站在更高的抽象层次上对集合进行操作.

Stream是一个接口中提供的方法参数大都是函数接口。

大多数常见方法返回值为Stream,可以对数据进行链式连续操作,也即函数式编程,对数据的处理逻辑十分清晰。

在Stream这一知识点下,也有一些十分高级的用法,如支持自定义收集器等,

我对其的理解和使用还停留在一个比较低的水平,所以下面的解释也都比较浅显易懂,

Stream从外部迭代到内部迭代

从一个例子说起

int count = 0;
for(Animal animal:allAnaimals){
    if("dog".equals(animal.type)){
        count++;
    }
}

单一的for循环理解起来还是十分简单,但当多重循环进行嵌套,for循环和while循环混合在一起,则又是另一番天地了。

就其背后的原理来看,for 循环其实是一个封装了迭代的语法糖,我们在这里多花点时间, 看看它的工作原理。首先调用 iterator 方法,产生一个新的 Iterator 对象,进而控制整个迭代过程,这就是外部迭代。迭代过程通过显式调用 Iterator 对象的 hasNext 和 next 方法完成迭代。解释代码如下

int count = 0;
Iterator<Animal> it = allAnimals.iterator();
while(it.hasNext()){
    Animal animal = it.next();
    if("dog".equals(animal.type)){
        count++;
    }
}

image-20220110124657631

使用stream的表达方式

int count = allAnimals.stream().filter(animal -> "dog".equals(animal.type)).count();

image-20220110124905687

stream() 方法的调用,它和调用 iterator() 的作用一样。该方法不是返回一个控制迭代的 Iterator 对象,而是返回内部迭代中的相应接口:Stream

Stream常用方法

filter

从一堆数据中基于一定的条件筛选出自己的目标数据,基本数据类型,复杂类型都可

从数据中筛选出大于5的数

@Test
public void test01(){
    List<Integer> nums = Arrays.asList(1,2,10,5,6,7,8,9);
    List<Integer> collect = nums.stream().filter(x -> x > 5).collect(Collectors.toList());
    collect.forEach(item -> System.out.println(item));
}

map

一种映射操作,就相当于函数 f(x)=y,根据自己的逻辑,将某一数据转换成另一种数据类型,基本数据类型之间,复杂数据类型之间,均可

将map中的每一个元素映射为它的值,并对它进行求和

    @Test
    public void test02(){
        Map<String,Integer> map = new HashMap<>();
        for(int i=0;i<10;i++){
            map.put(String.valueOf(i),i);
        }
        Integer reduce = map.entrySet().stream().map(node -> node.getValue()).reduce(0, (acc, num) -> acc + num);
        System.out.println(reduce);
    }

flatMap

将经过map操作后的数据再进行一次映射,通常可以用来提取复杂数据的某个属性来代替这个数据

将两个list的流转换为一个流,然后统计0的个数

@Test
public void test03(){
    long count = Stream.of(Arrays.asList(0, 0, 0), Arrays.asList(1, 2, 3, 4, 5)).flatMap(nums -> nums.stream()).filter(x -> x == 0).count();
    System.out.println(count);
}

reduce

一种高级的数据操作,用它可以实现其他的函数,如max,min,count等

Optional<T> reduce(BinaryOperator<T> accumulator);

该方法的参数BinaryOperator也是函数式接口,所以支持lambda表达式,用来完成需要的逻辑操作,返回值为Optional类型,T与处理的数据类型保持一致。

T reduce(T identity, BinaryOperator<T> accumulator);

该方法与上面的方法基本相同,不同的是多了一个T identity,常被用来作为计算前的初值,参与逻辑处理

<U> U reduce(U identity,
             BiFunction<U, ? super T, U> accumulator,
             BinaryOperator<U> combiner);

第三种方法是上面方法的增强版,上面两种方法返回的值类型与处理的数据类型要保持一致,第三种方法支持类型的转换,如多个数相加,超过了int的范围,这个时候就可以使用第三种,将第一参数设为long类型,这样就不会溢出了可以得到正确的结果,而另外两种方法就不支持。

下面是使用reduce方法的测试

第一种reduce实现最大,最小,累计操作

@Test
public void test06(){
    Optional<Integer> max = Stream.of(1, 2, 3, 4, 5).reduce((a, b) -> a+b);
    // 这个是累计,取最大 a+b 改为 a>b?a:b 取最小 a<b?a:b
    System.out.println(max);
}

第二种reduce,实现带有初值参与的累计操作

@Test
public void test05(){
    int i = Stream.of(1, 2, 3, 4, 5).reduce(0, (a, b) -> a * b);
    }

这里初值为0,也就是正常的累加操作

第三种reduce,实现类型的转换

@Test
public void test07(){
    Long reduce = Stream.of(Integer.MAX_VALUE, Integer.MAX_VALUE).reduce(0L, (a, b) -> a + b, (a, b) -> null);
}

max

从一组数据中,取出基于某个评价指标的最大值

min

从一组数据中,取出基于某种评价指标的最小值

max和min方法演示

    @Test
    public void test04(){

//        optional 是final 不可修改

        // 使用comparator.comparing() 进行比较
        Optional<Integer> min = Stream.of(1, 2, 3, 4, 5, 0,-1).min(Comparator.comparing(i->i));
        Optional<Integer> max = Stream.of(1, 2, 3, 4, 5, 0,-1).max(Comparator.comparing(i->i));
        System.out.println(min);
        System.out.println(max);

        // 使用lambda表达式
        Optional<Integer> min1 = Stream.of(1, 2, 3).min((a, b) -> a - b);
        System.out.println(min1);
    }

collect

List<String> collected = Stream.of("a", "b", "c") n
.collect(Collectors.toList());

使用 collect(toList()) 方法从 Stream 中生成一个列表

collect() 支持多种收集器(可以根据数据的特点进行自定义收集),属于进阶知识,这里不详细展开。

其他知识点(不详细展开了,大家感兴趣,可以自己查阅资料学习)

方法引用

一种推荐使用的表示方法,类名::方法名 如String::length

惰性求值

最终不产生新集合的方法叫作惰性求值方法;而像 count 这样或者为空最终会从 Stream 产生值的方法叫作及早求值方法。

并行化流操作

Stream 并发操作

········

标签: JavaSE lambda Stream
最后更新:2022年2月12日

Csy

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

取消回复
文章目录
  • Stream从外部迭代到内部迭代
  • Stream常用方法
    • filter
    • map
    • flatMap
    • reduce
    • max
    • min
    • collect
  • 其他知识点(不详细展开了,大家感兴趣,可以自己查阅资料学习)
    • 方法引用
    • 惰性求值
    • 并行化流操作
    • Stream 并发操作

COPYRIGHT © 2021 caibucai.top. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

豫ICP备2021018055号