JavaSE23-函数式接口&Stream流
阅读原文时间:2023年07月08日阅读:1

1.1 函数式接口概述

概念

  有且仅有一个抽象方法的接口

如何检测一个接口是不是函数式接口

  @FunctionalInterface

  放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败

注意事项

  我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上该注解。

1.2 函数式接口作为方法的参数

1 public class RunnableDemo {
2 public static void main(String[] args) {
3 startRunnable(() -> {
4 System.out.println(Thread.currentThread().getName()+"启动了");
5 });
6 }
7
8 private static void startRunnable(Runnable r) {
9 new Thread(r).start();
10 }
11 }

在Runnable中有如下定义

1 @FunctionalInterface
2 public interface Runnable {
3 /**
4 * When an object implementing interface {@code Runnable} is used
5 * to create a thread, starting the thread causes the object's
6 * {@code run} method to be called in that separately executing
7 * thread.
8 *


9 * The general contract of the method {@code run} is that it may
10 * take any action whatsoever.
11 *
12 * @see java.lang.Thread#run()
13 */
14 public abstract void run();
15 }

1.3 函数式接口作为方法的返回值

1 import java.sql.Connection;
2 import java.util.ArrayList;
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.Comparator;
6
7 public class getComparetorDemo {
8 public static void main(String[] args) {
9 ArrayList list = new ArrayList<>();
10 list.add("aaa");
11 list.add("b");
12 list.add("dd");
13 list.add("cccc");
14
15 System.out.println("排序前:"+list);
16
17 Collections.sort(list,getComparetor());
18
19 System.out.println("排序后:"+list);
20 }
21
22 private static Comparator getComparetor() {
23 return (s1,s2) -> s1.length() - s2.length();
24 }
25 }

1.4 常用函数式接口之Supplier

Supplier接口

  Supplier接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。

构造方法

方法名

说明

T get()

按照某种实现逻辑(由Lambda表达式实现)返回一个数据

返回字符串

1 import java.util.function.Supplier;
2
3 public class SupplierDemo {
4 public static void main(String[] args) {
5 System.out.println(useSup(
6 () -> "hello world"
7 ));
8 }
9
10 private static String useSup(Supplier sup) {
11 return sup.get();
12 }
13 }

返回最大值

1 import java.util.function.Supplier;
2
3 public class SupplierDemo2 {
4 public static void main(String[] args) {
5 int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 21, 142, 11, 2241, 24};
6 int maxValue = useSup(() -> {
7 int max = arr[0];
8
9 for (int i = 0; i < arr.length; i++) { 10 if (max < arr[i]) { 11 max = arr[i]; 12 } 13 } 14 15 return max; 16 }); 17 18 System.out.println(maxValue); 19 } 20 21 private static Integer useSup(Supplier sup) {
22 return sup.get();
23 }
24 }

1.5 常用函数式接口之Consumer

Consumer接口

  Consumer接口也被称为消费型接口,它消费的数据的数据类型由泛型指定

常用方法

方法名

说明

void accept(T t)

对给定的参数执行此操作

default Consumer andThen(Consumer after)

返回一个组合的Consumer,依次执行此操作,然后执行after操作

1 import java.util.function.Consumer;
2
3 public class ConsumerDemo {
4 public static void main(String[] args) {
5 String[] list = {"1,绿巨人","2,钢铁侠","3,美国队长"};
6
7 printinfo(list,str -> System.out.print("序号"+str.split(",")[0]),str -> System.out.println(str.split(",")[1]));
8 }
9
10 public static void printinfo(String[] list, Consumer con1,Consumer con2){
11 for (String s : list){
12 con1.andThen(con2).accept(s);
13 }
14 }
15 }

1.6 常用函数式接口之Predicate

Predicate接口

  Predicate接口通常用于判断参数是否满足指定的条件

方法名

说明

boolean test(T t)

对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回 一个布尔值

default Predicate negate()

返回一个逻辑的否定,对应逻辑非

default Predicate and(Predicate other)

返回一个组合判断,对应短路与

default Predicate or(Predicate other)

返回一个组合判断,对应短路或

1 import java.util.function.Predicate;
2
3 public class PredicateDemo {
4 public static void main(String[] args) {
5 boolean a = check("hello world",s -> s.length()<5); 6 System.out.println(a); 7 8 boolean b = uncheck("hello world",s -> s.length()<5); 9 System.out.println(b); 10 } 11 12 private static boolean check(String s , Predicate pre){
13 return pre.test(s);
14 }
15
16 private static boolean uncheck(String s , Predicate pre){
17 return pre.negate().test(s);
18 }
19 }

1.7 常用函数式接口之Function

Function接口

  Function接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值

方法名

说明

R apply(T t)

将此函数应用于给定的参数

default Function andThen(Function after)

返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果

1 import java.util.function.Function;
2
3 public class FunctionDemo {
4 public static void main(String[] args) {
5 parseint("13729",s -> Integer.parseInt(s));
6 }
7
8 private static void parseint(String s, Function fun) {
9 int i = fun.apply(s);
10 System.out.println(i);
11 }
12 }

2.1 体验Stream流

1 import java.util.ArrayList;
2
3 public class FilterDemo {
4 public static void main(String[] args) {//将姓张且名字在两个字(不含两个)以上的名字加入另一个集合
5 ArrayList names = new ArrayList<>();
6
7 names.add("张无忌");
8 names.add("赵敏");
9 names.add("张三丰");
10 names.add("张果老");
11 names.add("张国立");
12 names.add("铁拐李");
13 names.add("张赫");
14 names.add("张飞");
15 names.add("张翼德");
16 names.add("刘备");
17 names.add("关云长");
18 names.add("曹孟德");
19 names.add("吕轻侯");
20
21 ArrayList zhanglist = new ArrayList<>();
22
23 names.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() >=3).forEach(System.out::println);
24 }
25 }

Stream流的好处

  直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印

  Stream流把真正的函数式编程风格引入到Java中

2.2 Stream流的常见生成方式

生成Stream流的方式

  Collection体系集合

    使用默认方法stream()生成流, default Stream stream()

  Map体系集合

    把Map转成Set集合,间接的生成流

  数组

    通过Stream接口的静态方法of(T… values)生成流

1 import java.util.*;
2 import java.util.stream.Stream;
3
4 public class CreateStream {
5 public static void main(String[] args) {
6 //Collection体系直接使用stream()
7 List list = new ArrayList<>();
8 Stream listStream = list.stream();
9
10 Set set = new TreeSet<>();
11 Stream setStream = set.stream();
12 //Map体系间接生成
13 Map map = new HashMap<>();
14 Stream keyStream = map.keySet().stream();
15 Stream valueStream = map.values().stream();
16
17 Stream> entryStream = map.entrySet().stream();
18 //数组使用Stream接口的of()
19 String[] nums = {"1","2","3","4"};
20 Stream numStringStream = Stream.of(nums);
21 Stream numStram = Stream.of(1,2,3,4,5);
22 }
23 }

2.3 Stream流中间操作方法

概念

  中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作。

常用方法

方法名

说明

Stream filter(Predicate predicate)

用于对流中的数据进行过滤

Stream limit(long maxSize)

返回此流中的元素组成的流,截取前指定参数个数的数据

Stream skip(long n)

跳过指定参数个数的数据,返回由该流的剩余元素组成的流

static Stream concat(Stream a, Stream b)

合并a和b两个流为一个流

Stream distinct()

返回由该流的不同元素(根据Object.equals(Object) )组成的流

Stream sorted()

返回由此流的元素组成的流,根据自然顺序排序

Stream sorted(Comparator comparator)

返回由该流的元素组成的流,根据提供的Comparator进行排序

Stream map(Function mapper)

返回由给定函数应用于此流的元素的结果组成的流

IntStream mapToInt(ToIntFunction mapper)

返回一个IntStream其中包含将给定函数应用于此流的元素的结果

limit&skip

1 import java.util.ArrayList;
2
3 public class limitandskipDemo {
4 public static void main(String[] args) {
5 ArrayList names = new ArrayList<>();
6
7 names.add("张无忌");
8 names.add("赵敏");
9 names.add("张三丰");
10 names.add("张果老");
11 names.add("张国立");
12 names.add("铁拐李");
13 names.add("张赫");
14 names.add("张飞");
15 names.add("张翼德");
16 names.add("刘备");
17 names.add("关云长");
18 names.add("曹孟德");
19 names.add("吕轻侯");
20
21 //输出前三个
22 names.stream().limit(3).forEach(System.out::println);
23 System.out.println("-------");
24 //跳过三个然后输出
25 names.stream().skip(3).forEach(System.out::println);
26 System.out.println("-------");
27 //跳过四个输出五个
28 names.stream().skip(4).limit(5).forEach(System.out::println);
29 }
30 }

concat&distinct

1 import java.util.ArrayList;
2 import java.util.stream.Stream;
3
4 public class concatanddistinctDemo {
5 public static void main(String[] args) {
6 ArrayList names = new ArrayList<>();
7 names.add("张无忌");
8 names.add("赵敏");
9 names.add("张三丰");
10 names.add("张果老");
11 names.add("张国立");
12 names.add("铁拐李");
13
14 //截取前四个为流s1
15 Stream s1 = names.stream().limit(4);
16 //跳过前两个为流s2
17 Stream s2 = names.stream().skip(2);
18 //合并s1,s2
19 // Stream.concat(s1, s2).forEach(System.out::println);
20 //合并并去重
21 Stream.concat(s1, s2).distinct().forEach(System.out::println);
22 }
23 }

sort

1 import java.util.ArrayList;
2
3 public class sortDemo {
4 public static void main(String[] args) {
5 ArrayList names = new ArrayList<>();
6 names.add("张无忌");
7 names.add("赵敏");
8 names.add("张三丰");
9 names.add("张果老");
10 names.add("张国立");
11 names.add("铁拐李");
12
13 names.stream().sorted((s1,s2) -> {
14 int num = s1.length()-s2.length();
15 int num2 = num == 0 ? s2.compareTo(s1) : num;
16 return num2;
17 }).forEach(System.out::println);
18 }
19 }

maptoInt

1 import java.util.ArrayList;
2
3 public class maptointDemo {
4 public static void main(String[] args) {
5 ArrayList nums = new ArrayList<>();
6 nums.add("1");
7 nums.add("10");
8 nums.add("100");
9 nums.add("1000");
10 nums.add("10000");
11 nums.add("100000");
12
13 int result = nums.stream().mapToInt(Integer::parseInt).sum();
14 System.out.println(result);
15 }
16 }

count

1 import java.util.ArrayList;
2
3 public class countDemo {
4 public static void main(String[] args) {
5 ArrayList names = new ArrayList<>();
6
7 names.add("张无忌");
8 names.add("赵敏");
9 names.add("张三丰");
10 names.add("张果老");
11 names.add("张国立");
12 names.add("铁拐李");
13 names.add("张赫");
14 names.add("张飞");
15 names.add("张翼德");
16 names.add("刘备");
17 names.add("关云长");
18 names.add("曹孟德");
19 names.add("吕轻侯");
20
21 long count = names.stream().filter(s -> s.startsWith("张")).count();
22 System.out.println(count);
23 }
24 }

练习

这里有两个集合,有6个男演员和6个女演员,要求:

  男演员只要名字为3个字的前三人

  女演员只要姓林的,并且不要第一个

  把过滤后的男演员姓名和女演员姓名合并到一起

  把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据

Actor类

1 public class Actor {
2 private String name;
3
4 public Actor(String name) {
5 this.name = name;
6 }
7
8 public String getName() {
9 return name;
10 }
11
12 public void setName(String name) {
13 this.name = name;
14 }
15 }

实现类

1 import java.util.ArrayList;
2 import java.util.stream.Stream;
3
4 public class ActorControl {
5 public static void main(String[] args) {
6 ArrayList man = new ArrayList<>();
7 ArrayList woman = new ArrayList<>();
8
9 man.add("刘德华");
10 man.add("成龙");
11 man.add("周星驰");
12 man.add("周润发");
13 man.add("李小龙");
14 man.add("林正英");
15
16 woman.add("林青霞");
17 woman.add("关之琳");
18 woman.add("朱茵");
19 woman.add("林志玲");
20 woman.add("林心如");
21 woman.add("王祖贤");
22
23 //男演员只要名字为3个字的前三人
24 Stream manStream = man.stream().filter(s -> s.length() == 3).limit(3);
25 //女演员只要姓林的,并且不要第一个
26 Stream womanStream = woman.stream().filter(s -> s.startsWith("林")).skip(1);
27 //把过滤后的男演员姓名和女演员姓名合并到一起
28 Stream stream = Stream.concat(manStream, womanStream);
29 //把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
30 stream.map(Actor::new).forEach(s -> System.out.println(s.getName()));
31 }
32 }

或者更简便的写法

1 import java.util.ArrayList;
2 import java.util.stream.Stream;
3
4 public class ActorControl {
5 public static void main(String[] args) {
6 ArrayList man = new ArrayList<>();
7 ArrayList woman = new ArrayList<>();
8
9 man.add("刘德华");
10 man.add("成龙");
11 man.add("周星驰");
12 man.add("周润发");
13 man.add("李小龙");
14 man.add("林正英");
15
16 woman.add("林青霞");
17 woman.add("关之琳");
18 woman.add("朱茵");
19 woman.add("林志玲");
20 woman.add("林心如");
21 woman.add("王祖贤");
22
23 Stream.concat(man.stream().filter(s -> s.length() == 3).limit(3),woman.stream().filter(s -> s.startsWith("林")).skip(1)).map(Actor::new).forEach(s -> System.out.println(s.getName()));
24 }
25 }

2.4 Stream流的收集操作

概念

  对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中。

常用方法

方法名

说明

R collect(Collector collector)

把结果收集到集合中

工具类Collectors提供了具体的收集方式

方法名

说明

public static Collector toList()

把元素收集到List集合中

public static Collector toSet()

把元素收集到Set集合中

public static Collector toMap(Function keyMapper,Function valueMapper)

把元素收集到Map集合中

1 import java.util.ArrayList;
2 import java.util.List;
3 import java.util.Map;
4 import java.util.Set;
5 import java.util.stream.Collectors;
6 import java.util.stream.Stream;
7
8 public class CollectorsDemo {
9 public static void main(String[] args) {
10 List names = new ArrayList<>();
11 names.add("张无忌");
12 names.add("赵敏");
13 names.add("张三丰");
14 names.add("张果老");
15 names.add("张国立");
16 names.add("铁拐李");
17 names.add("张赫");
18 names.add("张飞");
19 Stream nameStream = names.stream().filter(s -> s.length()==3);
20 List threeWordsNames = nameStream.collect(Collectors.toList());
21 for (String s : threeWordsNames){
22 System.out.println(s);
23 }
24 System.out.println("------");
25 Stream namesStreams = names.stream().filter(s ->s.startsWith("张"));
26 Set threeNames = namesStreams.collect(Collectors.toSet());
27 for (String sm : threeNames){
28 System.out.println(sm);
29 }
30 System.out.println("------");
31 String[] strArray = {"1,张曼玉","2,林青霞","3,朱茵"};
32 Stream strStream = Stream.of(strArray);
33 Map bf = strStream.collect(Collectors.toMap(s -> s.split(",")[0],s -> s.split(",")[1]));
34 Set keys = bf.keySet();
35 for (String key : keys){
36 String value = bf.get(key);
37 System.out.println(value);
38 }
39 }
40 }