02-函数式接口

函数式编程:函数的参数也是函数,函数返回的也是函数。

概念:如果一个接口只有 1 个公开抽象方法,则该接口为函数式接口。

  • 为了确保接口达到只有1个方法的要求,接口名上添加注解 @FunctionalInterface
  • Java8内置 4 个核心函数式接口interface。
    位置:java.util.function
1
2
3
4
5
6
7
8
9
10
11
12
public class TestMethodInterface {
public static void main(String[] args) {
// 接口引用 指向 Lambda表达式的匿名内部类对象
Interface t = ()->System.out.println("函数式编程...");
t.m(); // 函数式编程...
}
}

@FunctionalInterface
interface Interface {
void m();
}

① Predicate 接口(断言、返回真假)

根据赋值的Lambda表达式逻辑,用作一个参数的断言(布尔值函数)
成员方法:

1
2
3
4
5
6
7
8
9
10
boolean test(T t)
在给定的参数上执行这个断言逻辑。
default Predicate<T> and(Predicate<? super T> other)
返回一个组合的断言,表示该断言与另一个断言的短路逻辑AND。
static <T> Predicate<T> isEqual(Object targetRef)
返回根据 Objects.equals(Object, Object)测试两个参数是否相等的 断言 。
default Predicate<T> negate()
返回表示此断言的逻辑否定的断言。
default Predicate<T> or(Predicate<? super T> other)
返回一个组合的断言,表示该断言与另一个断言的短路逻辑或。

基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
Predicate<String> p1 = str -> str.length() == 9; // 字符串长度是否等于9
Predicate<String> p2 = str -> str.startsWith("j"); // 是否以j开头
Predicate<String> p3 = p1.and(p2); // 字符串是否长度为9并且以j开头
Predicate<String> p4 = p1.or(p2); // 字符串是否长度为9或者以j开头
Predicate<String> p5 = p1.negate(); // 字符串长度是否不等于9
Predicate<String> p6 = Predicate.isEqual("Java"); // 字符串是否等于Java
System.out.println(p1.test("aaa")); // false
System.out.println(p2.test("java")); // true
System.out.println(p3.test("jjjaaabbb"));// true
System.out.println(p4.test("ja"));// true
System.out.println(p5.test("123456789"));// false
System.out.println(p6.test("java"));// false

函数传参:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class TestPredicate {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");
list.add("zhangqi");

// Predicate断言:过滤出来已zhang开头的元素
List<String> ls = filter(list, (s)->s.startsWith("zhang"));
for (String string : ls) {
System.out.print(string + " "); // zhangsan zhangqi
}
}

public static List<String> filter(List<String> list, Predicate<String> p) {
List<String> l = new ArrayList<String>();
for (String s : list) {
if (p.test(s)) {
l.add(s);
}
}
return l;
}
}

② Consumer 接口(消费、有去无回)

根据赋值的Lambda表达式逻辑,接受单个输入参数并且不返回结果的操作。
成员方法:

1
2
3
4
void accept(T t)
对给定的参数执行此操作。
default Consumer<T> andThen(Consumer<? super T> after)
返回一个组合的 Consumer ,按顺序执行该操作,然后执行 after操作。

基本使用:

1
2
3
4
5
// 消费:给其内容,不关心其作何使用,没有返回值
Consumer<String> c = s->System.out.println(s);;
c.accept("hello world!"); // hello world!
// andThen后执行
c.andThen(s->System.out.println("hello," + s)).accept("world"); // world hello,world

函数传参:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.function.Consumer;
public class TestConsumer {
public static void main(String[] args) {
m1(100, (a)->System.out.println("今天挣钱了:" + a)); // 今天挣了100

m2(10, (a)->{
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}); // 0 1 2 3 4 5 6 7 8 9
}
public static void m1(double money, Consumer<Double> consumer) {
consumer.accept(money);
}
public static void m2(int num, Consumer<Integer> consumer) {
consumer.accept(num);
}
}

③ Supplier 接口(创造、无中生有)

根据赋值的Lambda表达式逻辑,根据只有1个抽象方法T get(),没有参数,返回一个T类型的结果。
成员方法:

1
2
T get()
获得结果。

基本使用:

1
2
Supplier<Double> sup = ()->new Double(Math.random());
System.out.println( sup.get() ); // 输出1个随机<1的小数

函数传参:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.Random;
import java.util.function.Supplier;
public class TestSupplier {
public static void main(String[] args) {
int result = getSum(10, ()->new Random().nextInt(100));
System.out.println(result); // 10个100以内随机整数的和

Supplier<Integer> sup = ()->{
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
};
System.out.println("1-100的和:" + sup.get()); // 5050
}

public static int getSum(int num, Supplier<Integer> supplier) {
int sum = 0;
for (int i = 0; i <= num; i++) {
sum += supplier.get();
}
return sum;
}
}

④ Function 接口(传递、返回数据)

根据赋值的Lambda表达式逻辑,计算T类型的值,返回R类型的值。
成员方法:

1
2
3
4
5
6
7
8
R apply(T t)
将此函数应用于给定的参数。
default <V> Function<T,V> andThen(Function<? super R,? extends V> after)
返回一个组合函数,首先将该函数应用于其输入,然后将 after函数应用于结果。
default <V> Function<V,R> compose(Function<? super V,? extends T> before)
返回一个组合函数,首先将 before函数应用于其输入,然后将此函数应用于结果。
static <T> Function<T,T> identity()
返回一个总是返回其输入参数的函数。

基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
// String 为传入 Lambda 表达式参数的类型T,Integer 为返回值的类型R
Function<String, Integer> up1 = (s)->s.length();
System.out.println( up1.apply("hello") ); // 5
// 将 up1 的 lambda 运行后,作为结果再执行 up2,组合在一起
Function<String, String> up2 = (s)->"aaa" + s;
System.out.println( up1.compose(up2).apply("12345") ); // 3+5==8
// 将 up2 的 lambda 运行后,作为结果然后再执行 apply
Function<String, String> up3 = (s)->"bbb" + s;
System.out.println( up3.andThen(up2).apply("11111") ); // aaabbb11111
// identity() 静态方法,总是返回其输入的参数
Function<String, String> up4 = Function.identity();
System.out.println( up4.apply("Jerry") );

函数传参:

1
2
3
4
5
6
7
8
9
10
11
import java.util.function.Function;
public class TestFunction {
public static void main(String[] args) {
String up = stringUpper("hello,world", (s)->s.toUpperCase());
System.out.println(up); // HELLO,WORLD
}

public static String stringUpper(String s, Function<String, String> fun) {
return fun.apply(s);
}
}

02-函数式接口
https://janycode.github.io/2016/04/28/02_编程语言/01_Java/02_Java8/02-函数式接口/
作者
Jerry(姜源)
发布于
2016年4月28日
许可协议