前言
在 lambda 中了解了什么是函数式接口,以及 @FunctionalInterface 注解。
我们知道函数式接口中,有且只有一个抽象方法的接口,但可以有多个非抽象方法的接口。
而 @FunctionalInterface 注解是可以检查一个接口是否为函数式接口。只是在编译时强制规范使用。 如果接口是函数接口,编译通过;如果不是,编译失败。
我们自定义函数式接口时,@FuncationalInterface 注解是可选的,就算我们不写这个注解,只要保证是函数式接口也是可以的。但是建议加上。
Java 8 在 java.util.function 包下预定了大量的函数式接口供我们使用。常用的有:
- 生产型 Supplier 接口
- Function 接口
- Consumer 接口
- Predicate 接口
生产型 Supplier
java.util.function.Supplier<T> 接口仅包含一个无参的方法 T get()。用来获取一个泛型参指定类型的对象数据。
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
案例
@Test
public void test() {
String string = supplierGet(() -> {
return "supplier test";
});
System.out.println(string);
}
private static <T> T supplierGet(Supplier<T> sup) {
return sup.get();
}
消费型 Consumer
java.util.function.Consumer<T> 接口与 Supplier 接口相反,它是消费一个数据,不产生输出,其类型是一个泛型。Consumer 中包含抽象方法void accept(T t) 意思接受一个指定泛型的数据进行处理,此外还有一个默认实现方法 Consumer<T> andThen(Consumer<? super T> after)。
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
案例_accept
@Test
public void test() {
consumerAccept("qweqweqwe", (item) -> {
String s = new StringBuilder(item.toString()).reverse().toString();
System.out.println(s);
});
}
private static <T> void consumerAccept(T name, Consumer<T> com) {
com.accept(name);
}
}
这里无论 Consumer 都会将其做一次反转后,进行打印。
案例_andThen
@Test
public void test2() {
consumerAndThen("qwE123", (item) -> {
System.out.println("先执行了我");
String s = new StringBuilder(item.toString()).reverse().toString();
System.out.println(s);
}, item -> {
System.out.println("后执行了我");
String s = item.toUpperCase().toLowerCase();
System.out.println(s);
});
}
private static <T> void consumerAndThen(T name, Consumer<T> com, Consumer<T> com2) {
com.andThen(com2).accept(name);
}
输出结果
先执行了我
321Ewq
后执行了我
qwe123
这里需要注意的点是:
- 都是对原数据进行了操作,如果是基本类型值不变,如果是引用对象,只修改了引用对象的内部值。
- 在
consumer内部修改方法剧本变量的值,会提示异常Variable used in lambda expression should be final or effectively final。这是一个隐式的final。 - 这里可以做链式消费数据,但是需要主要处理对象的主体。
判断型 Predicate
java.util.function.Predicate<T> 接口是接受一个特定泛型的数据,从而获得一个 boolean 结果。其中包含一个抽象方法 boolean test(T t), 根据传入参数做检查后,返回true/false。2
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
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);
}
}
案例_test
@Test
public void test() {
boolean checkBool = predicateTest("str", item -> {
if (item instanceof String) {
return true;
}
return false;
});
System.out.println(checkBool);
}
private static <T> boolean predicateTest(T obj, Predicate<T> predicate) {
return predicate.test(obj);
}
案例_negate
Predicate 提供了一个 negate,意为取反,即将返回boolean进行非处理。
@Test
public void tes2() {
boolean checkBool = predicateNegate("str", item -> {
if (item instanceof String) {
return true;
}
return false;
});
System.out.println(checkBool);
}
private static <T> boolean predicateNegate(T obj, Predicate<T> predicate) {
// 等效于 !predicate.test(obj);
return predicate.negate().test(obj);
}
案例_and
Predicate 接口中有一个方法 and,表示并且关系,同时满足返回 TRUE。
/**
* 1. 判断是否为String类型
* 2. 判断是否以STR开始
* 两个调价你必须同时满足
*/
@Test
public void tes3() {
boolean checkBool = predicateAnd(Integer.valueOf(123), item -> {
System.out.println("type");
if (String.class.isInstance(item) ) {
return true;
}
return false;
}, item -> {
System.out.println("starts");
if (item.toString().toUpperCase().startsWith("STR")) {
return true;
}
return false;
});
System.out.println(checkBool);
}
private static <T> boolean predicateAnd(T obj, Predicate<T> predicate, Predicate<T> predicate2) {
// 等效于 predicate.test(obj) && predicate2.test(obj);
return predicate.and(predicate2).test(obj);
}
案例_or
Predicate 接口中有一个方法 or,表示或关系,满足一个返回 TRUE。
/**
* 1. 判断是否为Integer类型
* 2. 判断是否以STR开始
* 两个条件满足一个
*/
@Test
public void test4() {
boolean checkBool = predicateOr(String.valueOf("STR111"), item -> {
System.out.println("type");
if (Integer.class.isInstance(item)) {
return true;
}
return false;
}, item -> {
System.out.println("starts");
if (item.toString().toUpperCase().startsWith("STR")) {
return true;
}
return false;
});
System.out.println(checkBool);
}
private static <T> boolean predicateOr(T obj, Predicate<T> predicate, Predicate<T> predicate2) {
// 等效于 predicate.test(obj) || predicate2.test(obj);
return predicate.or(predicate2).test(obj);
}
类型转换 Function
ava.util.function.Function<T,R> 用来根据一个类型的数据得到另一个类型的数据,前者 T 称为前置条件/传入参数,后者 R 成为后置条件/返回参数。提供了一个最主要的抽象方法 R apply(T t),根据 T 类型的数据获取 R 类型的结果。使用场景:类型转换。
@FunctionalInterface
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;
}
}
案例_apply
@Test
public void test() {
Integer integer = functionTest("123123", item -> {
return Integer.valueOf(item);
});
System.out.println(integer);
}
public static <T, R> R functionTest(T obj, Function<T, R> function) {
return function.apply(obj);
}
案例_compose
接口中的默认方法 compose 用来进行组合操作。传入一个 function 先执行,并将处理结果传入下一个 function
/**
* 1. 执行apply(4),将“4” 传入到fc2 转换为 Integer输出
* 2. 在执行fc1 的apply方法,将Integer 4传入。
*/
@Test
public void test2() {
Function<Integer, Integer> fc1 = i -> i * 2;
Function<String, Integer> fc2 = i -> Integer.valueOf(i);
System.out.println(fc1.compose(fc2).apply("4"));
}
案例_andThen
默认方法 andThen 用来进行组合操作。传入一个 function 后执行,并将处理结果传入下一个 function。与compose 功能相反,andThen 添加到后面执行,compose 插入到前面执行
/**
* 1. 接收到 int 4 后,乘以2后,得出8返回
* 2. 将 int 8 传入,转换为 String 返回
*/
@Test
public void test3() {
Function<Integer, Integer> fc1 = i -> i * 2;
Function<Integer, String> fc2 = i -> i + "";
System.out.println(fc1.andThen(fc2).apply(4));
}