函数式接口
函数式接口是指:有且只有一个抽象方法的接口,当然接口中可以有默认方法、私有方法和静态方法。
@FunctionalInterface
这个注解的作用是标注该接口是一个函数式接口,如果该接口不是函数式接口,就会飘红编译报错。
@FunctionalInterface
public interface Demo {
void method();
}
@FunctionalInterface
public interface Demo {
void method();
void method2();
}
Lambda表达式和匿名内部类的区别
Lambda表达式不止是匿名内部类的语法糖,它的本质上和匿名内部类会有区别。
匿名内部类性能比lambda表达式低,因为匿名内部类会创建一个类似于动态代理类的class文件。
Lambda表达式的一般使用场景
1、Lambda表达式一般常作为方法的参数使用,某个方法的形参是一个函数式接口,在该方法中调用该接口的方法,该方法在传参时由Lambda表达式提供实现,这是策略模式。
2、Lambda表达式可以封装成一个方法,作为返回值return回去。
Supplier接口
JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在 java.util.function 包中被提供。
// Supplier接口源码
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
java.util.function.Supplier 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对象数据。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
Supplier接口被称为生产型接口,指定接口的泛型,则改接口的get方法就应该生产什么类型的数据。
// 通过Supplier接口获取数组中的最大值
public class Demo {
public static int getMax(Supplier<Integer> sup) {
return sup.get();
}
public static void main(String[] args) {
int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8};
int result = getMax(() -> {
int max = arr[0];
for (int i : arr) {
if (i > max) {
max = i;
}
}
return max;
});
System.out.println(result);
}
}
Consumer接口
Consumer接口与Supplier接口相反,它不生产一个数据,而是消费一个数据,消费的数据类型同样由泛型指定。
而怎么去消费,由调用该方法是传入的lambda体具体指定。
// Consumer接口源码
@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); };
}
}
// 通过Consumer接口使用
public class ConsumerDemo {
public static void consumerStr(Consumer<String> consumer) {
consumer.accept("this is consumer param"); // 这里指定参数
}
public static void main(String[] args) {
consumerStr(param -> System.out.println(param)); // 这里指定Consumer.accept()的具体实现(使用策略)
}
}
// 由于System.out.println,println方法是out对象的已有实现
// 因此可优化为方法引用
public class ConsumerDemo {
public static void consumerStr(Consumer<String> consumer) {
consumer.accept("this is consumer param");
}
public static void main(String[] args) {
consumerStr(System.out::println);
}
}
Predicate接口
Predicate接口用于对指定泛型的数据进行判断,进而得到一个boolean结果。
//Predicate接口源码
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
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);
}
}
// 通过Predicate接口使用
public class PredicateDemo {
public static void method(Predicate<String> predicate) {
boolean result = predicate.test("hello");
System.out.println(result);
}
public static void main(String[] args) {
method(str -> str.length() > 5);
}
}
默认方法:and
// 如果使用Predicate.test判断时需要同时满足两个条件
public class PredicateDemo {
public static void methodAnd(Predicate<String> one, Predicate<String> two) {
boolean result = one.and(two).test("hello");
System.out.println(result);
}
public static void main(String[] args) {
methodAnd(str -> str.length() > 5, str -> str.length() < 10);
}
}
默认方法:or
// 与and同理,不再赘述
默认方法:negate
该方法对Predicate.test()方法结果取反,注意:negate方法要在test方法之前调用。
// 使用negate对test取反
public class PredicateDemo {
public static void methodNegate(Predicate<String> one) {
boolean resultNegate = one.negate().test("hello");
System.out.println(resultNegate);
}
public static void main(String[] args) {
methodNegate(s -> s.length() > 5);
}
}
Function接口
Function接口用来根据一个类型的数据得到另一个类型的数据,前者被称为前置条件,后者被称为后置条件。
当然这两个数据类型可以一致。
改接口常用于数据转换、处理、格式化等,总之用于将数据从一种状态转换成另一种状态。
// Function接口源码
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
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;
}
}
// Function接口的使用
public class FunctionDemo {
public static Integer method(Function<String, Integer> function) {
return function.apply("1");
}
public static String method2(Function<String, String> function) {
return function.apply("1");
}
public static void main(String[] args) {
System.out.println(method(Integer::parseInt));
System.out.println(method2(s -> s + "!!!"));
}
}
方法引用
当要传递给lambda体的操作,已经有实现的方法了,就可以使用方法引用。
格式:
使用“::”将类(或对象)与方法名分隔开。
如:
对象::实例方法名
类::静态方法名
类::实例方法名
public class Demo {
public static void main(String[] args) {
test1();
}
private static void test1() {
// 常规写法
Consumer<String> con1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
// lambda表达式写法:
Consumer<String> con1 = str -> System.out.println(str);
/*
方法引用写法:
当要传递给lambda体的操作,已经有实现的方法了,就可以使用方法引用。
System.out 是 PrintStream对象
该对象的println方法已经有实现了
*/
Consumer<String> con1 = System.out::println;
// 控制台打印twz
con1.accept("twz");
}
}
方法引用本质上就是lambda表达式,而lambda表达式是函数式接口的实例,因此方法引用其实就是函数式接口的实例。