万字详解Stream流,聊聊工作中常用的Lambda表达式

前言


大家好,我是weichert。

在日常开发中,我们经常会用到JDK 8中的Lambda表达式,lambda表达式允许我们把函数作为一个方法的参数,实现复杂的功能。函数式编程相较于面向对象编程(OOP),可以使我们的代码更加简洁,更加优雅,可以使用更少的代码量,实现更加强大的功能。stream流针对于list的操作更加的简洁,集成了许多常用的api,供我们进行调用,极大的提高了我们的开发效率。在这篇文章中,我整理了在我工作中常用的一些Stream流,供大家学习参考。

  • 公众号、掘金账号: weichert

函数式接口原理


函数式接口是Java中的一种接口类型,它只包含一个抽象方法。使用@FunctionalInterface注解。,这个注解只可以标记在有且仅有一个抽象方法的接口上,并且JDK8接口中的静态方法和默认方法,都不算是抽象方法。常用函数式接口如Function等也随Lambda一同增加在了java.util.function包中。

在jdk8中底层的实现原理:在我们实际编写lambda表达式中,就是将该接口进行重写,我们只需要关注参数和返回值即可,例如Function中的参数泛型,返回值泛型。

jdk8中的函数式接口放在java.util.function目录下:

lambda表达式的写法


Java中lambda表达式符号:->

写法: (参数) -> {返回值}

生产型接口(无参数有返回值):( ) -> {业务代码,return 返回值}

消费型接口(有参数无返回值):(参数值) -> {业务代码,无返回值}

转换型接口(有参数有返回值):(参数值) -> {业务代码,return 返回值}

备注:

  • 当参数值只有一个时,()可以省略不写。 - 但业务代码只有一行时,{}可以省略不写。 - -> 符号,不可以省略。

示例:Thread类的函数式接口

java 复制代码
// 1.使用匿名内部类的方式创建多线程new Thread(new Runnable() {    @Override    public void run() {        System.out.println("这是多线程1");    }}).start();
// 2.使用lambda表达式的方式创建多线程表达式new Thread(() -> System.out.println("这是多线程2")).start();

Thread(函数式接口)

stream流常用方法


1.创建stream流

方式1:

java 复制代码
List<Integer> list = new ArrayList<>();Stream<Integer> stream = list.stream();

方式2:

java 复制代码
Stream<String> stream = Stream.of("张三", "李四", "王五");

备注: stream流创建后只能使用一次,创建了一个stream流使用两次会报IllegalStateException异常。

java 复制代码
@Testpublic void testReuseStream() {    Stream<Integer> stream = Stream.of(416, 1854, 157, 187);    stream.sorted().forEach(System.out::println);    stream.sorted(((o1, o2) -> o2-o1)).forEach(System.out::println);}

2.ForEach

forEach方法和Java中的for循环是一样,主要是是做遍历操作。**

**

该函数式接口为消费型接口,有参无返回值,并且是终结接口(表示处理结束)。

java 复制代码
public void testForEach(){        List<String> list = new ArrayList<String>() {{            add("1");            add("2");            add("3");        }};
        list.forEach(s-> System.out::println);    }

3.Collect

转化接口,我们经常使用该接口将stream流转换为list,该接口可以作为终结接口使用,collect(Collectors.toList())最常用。

java 复制代码
@Testpublic void testCollect(){    List<String> list = new ArrayList<String>() {{        add("1");        add("2");        add("2");    }};    //转换为新的list    List newList = list.stream().map(s -> Integer.valueOf(s)).collect(Collectors.toList());}

4.Filter

这是一个过滤方法,就像一个过滤器,满足条件的才会保存起来,不满足条件的就会被过滤掉。

该函数式接口,返回值是一个布尔值,为true则保存,为false则丢弃。

java 复制代码
public void testFilter() {        List<String> list = new ArrayList<String>() {{            add("1");            add("2");            add("3");        }};                        list.stream()                // 过滤掉我们希望留下来的值                // 表示我们希望字符串是 1 能留下来                // 其他的过滤掉                .filter(str -> "1".equals(str))                .collect(Collectors.toList());}

5.Map

map 方法可以让我们进行一些流的转化,比如原来流中的元素是 A,通过 map 操作,可以使返回的流中的元素是 B,这是一个转换方法。

这是方法是所有方法中使用频率最高的,常见的转化操作都会使用该接口,比如将String类型的数据转换为Integer类型

java 复制代码
public void testMap() {        List<String> list = new ArrayList<String>() {{            add("1");            add("2");            add("3");        }};        //通过 map 方法list中元素转化成 小写        List<String> strLowerList = list.stream()                .map(str -> str.toLowerCase())                .collect(Collectors.toList());}

6.Distinct

distinct 方法类似于SQL中的去重操作,可以去掉重复的参数。

备注:对于引用数据类型的去重需要重写hashCode和equals方法。

java 复制代码
public void testDistinct(){        List<String> list = new ArrayList<String>() {{            add("1");            add("2");            add("2");        }};        list.stream()                .map(s -> Integer.valueOf(s))                .distinct()                .collect(Collectors.toList());    }

7.Sorted

Sorted 方法提供了排序的功能,并且允许我们自定义排序,可以正序,倒序,自定义规则排序等。

8.findFirst

这个方法就像SQL中的limit1一样,只会返回集合中的第一个元素,在获取第一名,最后一名这种操作下,常见。**

**

java 复制代码
@Testpublic void testCollect(){    List<String> list = new ArrayList<String>() {{        add("1");        add("2");        add("2");    }};    //转换为新的list    Optional<Integer> first = list.stream().map(s -> Integer.valueOf(s)).sorted().findFirst();}

9.Max,Min

这两个方法顾名思义是求集合中的最大值、最小值。

java 复制代码
public void testMaxMin(){        List<String> list = new ArrayList<String>() {{            add("1");            add("2");            add("2");        }};
        list.stream().max(Comparator.comparing(s -> Integer.valueOf(s))).get();        list.stream().min(Comparator.comparing(s -> Integer.valueOf(s))).get();    }

10.groupingBy

groupingBy 是能够根据字段进行分组,toMap 是把 List 的数据格式转化成 Map 的格式,类似于SQL中的group by。

java 复制代码
public void testGroupBy(){        List<String> list = new ArrayList<String>() {{            add("1");            add("2");            add("2");        }};
        Map<String, List<String>> strList = list.stream().collect(Collectors.groupingBy(s -> {            if("2".equals(s)) {                return "2";            }else {                return "1";            }        }));    }

总结


本文中,主要描述了lambda表达式的实现原理,核心关键点在于函数式接口,以及函数式接口的分类,十种stream流的常用方法。

归根结底,在使用stream时,我们只需要关注函数式接口的参数和返回值即可,根据函数式接口的要求,实现我们的业务代码,即可优雅的使用函数式接口,简化我们的代码。

stream流中的方法和MySQL中的一些函数,关键字的作用类似,都是对数据的处理操作。

stream流和MySQL中函数的区别

stream流 MySQL
min,max min,max
findFirst limit 1
groupingBy grouping by********
distinct distinct
sorted order by
filter where

最后


stream的使用,也是熟能生巧的事,群里面有小伙伴在交流该问题:

可以在公众号联系我进群哦!

只要多多练习就能熟练的掌握stream流的使用,帮助你优雅地写出高质量的代码。

欢迎关注公众号:weichert

每天分享一篇实用的技术文章,对面试,工作都有帮助

如果您觉得有收获,记得点赞,转发,分享,谢谢

相关推荐
爬山算法15 分钟前
Maven(28)如何使用Maven进行依赖解析?
java·maven
hlsd#22 分钟前
go mod 依赖管理
开发语言·后端·golang
陈大爷(有低保)26 分钟前
三层架构和MVC以及它们的融合
后端·mvc
亦世凡华、26 分钟前
【启程Golang之旅】从零开始构建可扩展的微服务架构
开发语言·经验分享·后端·golang
河西石头27 分钟前
一步一步从asp.net core mvc中访问asp.net core WebApi
后端·asp.net·mvc·.net core访问api·httpclient的使用
2401_8574396939 分钟前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧66640 分钟前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
李老头探索42 分钟前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
芒果披萨1 小时前
Filter和Listener
java·filter
qq_4924484461 小时前
Java实现App自动化(Appium Demo)
java