Java函数式接口

函数式接口

刚接触完全不理解是个什么东西,但学了一会后有那么一点感觉这东西的好处了

对函数式接口的理解

我觉得这个东西就是为了简化代码,减轻内存压力的
如果为了使用一个方法而重新写一个类并实例化它,就会浪费内存去存储这个类
这时候,如果把这个方法变成一个函数,就可以简化代码,减少程序占的内存了

Supplier 接口

就是返回一个结果的参数
只有一个 get() 方法,用来获得结果
使用方法

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
String str = getString(()->{
return "demo";
});
System.out.println(str);
}
public static String getString(Supplier<String> sup){
return sup.get();
}

看代码有点难理解,我理解的执行过程是:

  1. 执行到 getString() 方法处,发现参数是一个 Supplier 接口
  2. 给 Supplier 接口传入一个 lambda 表达式,重写这个接口,并命名为 sup,进入函数中
  3. 调用 sup 的 get() 方法,返回这个结果
  4. 用 str 这个变量来接受这个返回结果
  5. 打印输出 str

Consumer 接口

接受单个输入参数并且不返回结果的操作,大概表示用一个传入的参数
有两个方法 accept 和 andThen
使用方法:

1
2
3
4
5
6
7
8
public static void main(String[] args) {
method("fuck me",(String str)->{
System.out.println("I say: "+ str);
});
}
public static void method(String name, Consumer<String> con){
con.accept(name);
}

执行流程和 Supplier 一样,都是重写了接口

andThen 方法就是可以一次可以使用多个 Consumer 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
String[] arr = {"buang,18", "kuang,20", "muang,17"};
method(arr,
(mess)->{
System.out.print("姓名: " + mess.split(",")[0]);
},
(mess)->{
System.out.println("年龄: " + mess.split(",")[1]);
}
);
}
public static void method(String[] arr, Consumer<String> con1, Consumer<String> con2){
for (String message : arr) {
//con1.accept(message)
//con2.accept(message) 分两次使用
con1.andThen(con2).accept(message); //一次性使用两个 Consumer
}
}

Predicate 接口

对给定的参数进行判断,并返回一个 boolean 值
基本的方法有 test,and(并且),or(或者),negate(取反)
使用方法

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
String str = "abc";
boolean b =check(str,(str1)->{
return str1.length()>5;
});
System.out.println(b);
}
public static boolean check(String str, Predicate<String> pre){
return pre.test(str);
}

对一 Predicate 接口的理解

  1. 执行到 check() 方法处,传入一个字符串,发现要传入一个 Predicate 的接口实现
  2. 重写 Predicate 的 test() 方法,可以使用 lambda 表达式
  3. 重写 test() 方法的判断标准是字符串长度大于5,由于 “abc” 长度小于5,返回 false
  4. 输出 false 这个结果

and 方法就是要两边都满足才判断为真,需要传入多个 Predicate 接口实现
实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
String s = "abandon";
boolean b = method(s, (str)->{
return str.length()>5;
},(str)->{
return str.contains("a"); //判断字符串是否含有字符 a
});
System.out.println(b);
}
public static boolean method(String str, Predicate<String> pre1, Predicate<String> pre2){
//return pre1.test(str) && pre2.test(str);
return pre1.and(pre1).test(str);
}

or 就是或,使用方法和 and 一样

1
return pre1.or(pre1).test(str);

negate 就是取反,非

1
return pre.negate().test(str);

Function 接口

接受一个参数并产生结果的函数
常用方法为 apply 和 andThen
使用方法

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
String str = "123456";
int result = method(str, (s)->{
return Integer.parseInt(s + 100);
});
System.out.println(result);
}
public static int method(String str, Function<String, Integer> fun){
return fun.apply(str);
}

method() 方法功能为传入一个数字字符串,经过一系列处理后,返回一个结果
andThen 方法的使用同 Consumer

1
2
3
4
5
6
7
8
9
10
11
12
public static void change(String str, Function<String, Integer> fun1, Function<Integer, String> fun2){
String ss = fun1.andThen(fun2).apply(str);
System.out.println(ss);
}
public static void main(String[] args) {
String str = "12345678";
change(str, (s)->{
return Integer.parseInt(s) + 10;
},(i)->{
return i + "";
});
}

change() 方法为传入一个字符串,将其转换为数字,并加10,再转换会字符串,并返回

定义函数式接口

定义一个接口,并宣称这是一个函数式接口,就是在最前面加上 @FunctionalInterface

1
2
3
4
@FunctionalInterface
public interface PrintStr {
void print(String s);
}

实例:

1
2
3
4
5
6
7
8
9
public static void method(PrintStr p){
p.print("hello world");
}

public static void main(String[] args) {
method((a)->{
System.out.println(a);
});
}

对执行步骤的理解:

  1. 执行主方法,发现 method 方法需要传入一个接口实现对象
  2. 传入一个 lambda 表达式,参数为a,这个 a 就是 print 方法的参数
  3. lambda 表达式就是接口的实现对象,也就是 method 中定义的参数 p
  4. p 调用接口的抽象方法 print 方法
  5. 重写了 print 方法为输出参数 a,也就是 method 中传入 print 方法的字符串
  6. 打印出字符串

在执行的过程中 a=”hello world”,传入的 lambda 表达式=p

1
2
3
4
5
6
7
8
9
10
public static void method(PrintStr p){
p.print("hello world");
}

public static void main(String[] args) {
method((a)->{
a="fuck me"; //修改参数 a 的值
System.out.println(a);
});
}

这里就是修改了参数 a 的值,重写了传入 print 方法的参数,这样就会打印 fuck me 了


感觉这个知识点会变成这样:
什么玩意?-> 有点懂了 -> 原来如此 -> 一段时间后 -> 什么玩意?
这个东西确实说难不难,理解起来也不难,但就是脑子转不过弯来,以后肯定会多次重新学习这个东西的
感觉这个也是一个在实际使用中很有用的玩意