前言
大家好,我是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
每天分享一篇实用的技术文章,对面试,工作都有帮助
如果您觉得有收获,记得点赞,转发,分享,谢谢