jdk8新特性之函数式接口

函数式接口

函数式接口是指:有且只有一个抽象方法的接口,当然接口中可以有默认方法、私有方法和静态方法。

@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表达式是函数式接口的实例,因此方法引用其实就是函数式接口的实例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值