本人在阅读Sa-token框架的时候,在研究全局策略的时候,发现了用到了大量的函数式接口,于是写下这篇文章巩固一下自己的知识点。
总所周知啊,Java在1.8的时候推出了函数接口,分别为Function(函数式接口),Supplier(供给式接口),Consumer(消费式接口),Predicate(断言式接口),这四个后面延申出BiFunction等等相应的函数接口。下面具体介绍。
Function接口
下面是Function的源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 public static void main(String[] args) {
Function<String, Integer> lengthFunction = str -> str.length();
Function<Integer, Integer> doubleFunction = length -> length * 2;
Integer doubleLength = doubleFunction.compose(lengthFunction).apply("www.wdbyte.com");
System.out.println(doubleLength);
}
//另一种写法
public static void main(String[] args) {
Function<String, Integer> lengthFunction = str -> str.length();
Function<Integer, Integer> doubleFunction = length -> length * 2;
Integer doubleLength = lengthFunction.andThen(doubleFunction).apply("www.wdbyte.com");
System.out.println(doubleLength);
}
//输出 28很显然,一般形式为
1
2
3
4
5
6
7
8
9 Function<T,R> varname = (T) ->{
操作...
return ans;
}
/*
apply来调用方法
compose和andThen用来连接其余Function方法
identity用来返回一个lambda方法
*/然后BiFunction相对于Function而言,接受的参数从一个变成两个
不过特殊的是,BiFunction的andThen方法可以接受Function参数,所以可以进一步抽象成更加通用的方法
比如工厂模式
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 //实体类
public class Dog {
private String name;
private Integer age;
public Dog() {
}
public Dog(String name, Integer age) {
this.name = name;
this.age = age;
}
// 省略 get set toString
}
import java.util.function.BiFunction;
public class JavaBiFunctionFactory {
public static void main(String[] args) {
System.out.println(dogFactory("牧羊犬", 1, Dog::new));
System.out.println(dogFactory("哈士奇", 2, Dog::new));
}
public static <R extends Dog> Dog dogFactory(String name, Integer age, BiFunction<String, Integer, R> biFunction) {
return biFunction.apply(name, age);
}
}
Supplier接口
下面是Supplier的源码,看起来非常的简单,就一个返回T
1
2
3
4
5
public interface Supplier<T> {
T get();
}由于不需要提供参数,所以可以很方便的用于对象创建
1
2
3
4
5
6
7
8
9
10
11
12 public class Java8Supplier {
public static void main(String[] args) {
Supplier<Integer> supplier = () -> new Random().nextInt(10);
System.out.println(supplier.get());
System.out.println(supplier.get());
Supplier<LocalDateTime> supplier2 = LocalDateTime::now;
System.out.println(supplier2.get());
System.out.println(supplier2.get());
}
}在 Java 8 中,为了方便
Supplier
的使用,提供了指定类型的Supplier
,有BooleanSupplier
,DoubleSupplier
,IntSupplier
,LongSupplier
,用这些来规定返回值类型。
Consumer接口
Consumer主要用来消费参数,但是不返回任何值
1
2
3
4
5
6
7
8
9
10
11
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
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 public class Java8Consumer {
public static void main(String[] args) {
Consumer<String> lengthConsumer = s -> System.out.println(s.length());
lengthConsumer.accept("Hello");
Consumer<String> printConsumer = System.out::println;
printConsumer.accept("Hello");
}
}
public class Java8ConsumerForEach {
public static void main(String[] args) {
Consumer<String> printConsumer = System.out::println;
List<String> list = Arrays.asList("java", "c#", "python");
forEach(list, printConsumer);
forEach(list, s -> System.out.println(s.length()));
}
public static <T> void forEach(List<T> list, Consumer<T> consumer) {
for (T t : list) {
consumer.accept(t);
}
}
}
函数接口 描述 BiConsumer 传入两个任意类型参数,无返回值 DoubleConsumer 传入一个 double 参数,无返回值 IntConsumer 传入一个 int 参数,无返回值 LongConsumer 传入一个 long 参数,无返回值 ObjDoubleConsumer 传入一个任意类型参数,一个 double 参数,无返回值 ObjIntConsumer 传入一个任意类型参数,一个 int 参数,无返回值 ObjLongConsumer 传入一个任意类型参数,一个 long 参数,无返回值
Predicate接口
这个是断言式接口,什么是断言,其实就是个判断语句,它接受一个T泛型参数,返回值为布尔类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {//使用 and() 方法,可以让前后两个 Predicate 判断条件一起生效。
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {//predicate.negate() 方法会返回一个与指定判断相反的 Predicate。
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {//使用 and() 方法,可以让前后两个 Predicate 判断条件都生效。
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
Predicate
的or()
,and()
,negate()
方法可以随意组合Predicate
,组合后的判断逻辑是从左到右,从前到后,顺次判断。
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 public class Java8PredicateChain {
public static void main(String[] args) {
List<Integer> numberList = Arrays.asList(3, 4, 5, 6, 7, 8, 9, 10);
Predicate<Integer> lessThan5 = number -> number <= 5;
Predicate<Integer> greaterThan9 = number -> number >= 9;
// 小于等于 5
System.out.println(filter(numberList, lessThan5));
// 大于 5
System.out.println(filter(numberList, lessThan5.negate()));
// 小于等于 5 或者大于等于 9
System.out.println(filter(numberList, lessThan5.or(greaterThan9)));
// ! (小于等于 5 AND 大于等于 9)
System.out.println(filter(numberList, lessThan5.and(greaterThan9).negate()));
}
public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
List<T> resultList = new ArrayList<>();
for (T t : list) {
if (predicate.test(t)) {
resultList.add(t);
}
}
return resultList;
}
}
UnaryOperator 接口
其实是Function接口的子类,唯一特点就是默认返回值是T,只接受一个参数T
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 public class Java8UnaryOperatorParams {
public static void main(String[] args) {
List<String> list = Arrays.asList("java", "node", "c++", "rust");
// 转大写
UnaryOperator<String> upperFun = s -> s.toUpperCase();
// 截取 3 位
UnaryOperator<String> subFun = s -> s.substring(0, 3);
List<String> resultList = map(list, upperFun, subFun);
System.out.println(resultList);
}
public static <T> List<T> map(List<T> list, UnaryOperator<T>... unaryOperator) {
List<T> resultList = new ArrayList<>();
for (T t : list) {
for (UnaryOperator<T> operator : unaryOperator) {
t = operator.apply(t);
}
resultList.add(t);
}
return resultList;
}
}ps:
这边有个知识点,在java中,…表示可变长度参数列表,表示接受的参数为0到多个Object类型的对象,或者是一个Object[]
可变长度参数列表必须作为最后一位参数!