Java8新特性之函数式接口

发布时间:2024年01月10日

JDK1.8 对函数式接口的描述

/**
 * An informative annotation type used to indicate that an interface
 * type declaration is intended to be a <i>functional interface</i> as
 * defined by the Java Language Specification.
 *
 * Conceptually, a functional interface has exactly one abstract
 * method.  Since {@linkplain java.lang.reflect.Method#isDefault()
 * default methods} have an implementation, they are not abstract.  If
 * an interface declares an abstract method overriding one of the
 * public methods of {@code java.lang.Object}, that also does
 * <em>not</em> count toward the interface's abstract method count
 * since any implementation of the interface will have an
 * implementation from {@code java.lang.Object} or elsewhere.
 *
 * <p>Note that instances of functional interfaces can be created with
 * lambda expressions, method references, or constructor references.
 *
 * <p>If a type is annotated with this annotation type, compilers are
 * required to generate an error message unless:
 *
 * <ul>
 * <li> The type is an interface type and not an annotation type, enum, or class.
 * <li> The annotated type satisfies the requirements of a functional interface.
 * </ul>
 *
 * <p>However, the compiler will treat any interface meeting the
 * definition of a functional interface as a functional interface
 * regardless of whether or not a {@code FunctionalInterface}
 * annotation is present on the interface declaration.
 *
 * @jls 4.3.2. The Class Object
 * @jls 9.8 Functional Interfaces
 * @jls 9.4.3 Interface Method Body
 * @since 1.8
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

从注释我们可以得出

  1. 函数式接口的实例可以使用lambda表示,方法引用或者构造函数引用
  2. 带有这个注解的type表示这是接口,而不是注解,枚举或者类
  3. 函数式接口可以不带这个注解,但是带上了这个注解却不是函数式接口的话,编译器将会报错

下面自定义一个自己的函数式接口 :

@FunctionalInterface
public interface  MyFunction {
	//只能有一个抽象方法
    public void handlerMyFunction();
	
    //接口默认方法 jdk1.8 新提供default特性
    default void handlerFunction() {
        System.out.println("this is my interface method");
    }
	//静态方法
    static void getFunction() {
        System.out.println("this is static method");
    }
}

default 是 jdk1.8提出的,思考一下为什么会提供这个功能?

在List接口中,我们可以看到如下方法。

default void replaceAll(UnaryOperator<E> operator) {
   Objects.requireNonNull(operator);
   final ListIterator<E> li = this.listIterator();
   while (li.hasNext()) {
       li.set(operator.apply(li.next()));
   }
}

default void sort(Comparator<? super E> c) {
       Object[] a = this.toArray();
       Arrays.sort(a, (Comparator) c);
       ListIterator<E> i = this.listIterator();
       for (Object e : a) {
           i.next();
           i.set((E) e);
       }
}

你会神奇的发现,List 从jdk1.2版本开始,使用了这么时间的接口,竟然能够通过default方法进行扩展接口的功能。

通过函数式接口接口的简单理解,那我们看下jdk1.8为我们提供了哪些接口

四大核心函数式接口

函数式接口参数类型返回参数使用场景
Consumer 消费型接口Tvoid对类型为 T 的对象应用操作,接口定义的方法:void accept(T t)
Supplier 供给型接口T返回类型为 T 的对象,接口定义的方法:T get()
Function<T, R>函数式接口TR对类型为 T 的对象应用操作,并 R 类型的返回结果。接口定义的方法:R apply(T t)
Predicate 断言型接口Tboolean确定类型为 T 的对象是否满足约束条件,并返回boolean 类型的数据 接口定义的方法:boolean test(T t)
1: Consumer 接口

Consumer 接口是消费性接口,无返回值

public class ConsumerFunction {
    public static void main(String[] args) {
        handlerConsumer(1000, (integer) -> {
            for (int i = 0; i < integer; i++) {
                System.out.println("number: " + i);
            }
        });
    }
    public static void handlerConsumer(Integer number, Consumer<Integer> consumer) {
        consumer.accept(number);
    }
}
2: Supplier 接口

Supplier 接口是供给型接口,有返回值

public class SupplierFunction {

    public static void main(String[] args) {
        List<Integer> numberList = getNumberList(10, () -> new Random().nextInt(100));
        System.out.println(numberList);
    }

    public static List<Integer> getNumberList(int num, Supplier<Integer> supplier) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add(supplier.get());
        }
        return list;
    }
}
3: Function接口

Function 接口是函数型接口,有返回值

public class FunctionFunction {
    public static void main(String[] args) {
        String hello = handlerString("hello", s -> s.toUpperCase());
        System.out.println(hello);
    }

    public static String handlerString(String str, Function<String, String> function) {
        return function.apply(str);
    }
}
4: Predicate接口

Predicate 接口是断言型接口,返回值类型为 boolean

public class PredicateFunction {
    public static void main(String[] args) {
        List<String> stringList = Arrays.asList("hello", "World", "Lambda", "Predicate");
        List<String> strings = filterString(stringList, str -> str.length() > 5);
        System.out.println(strings);
    }

    public static List<String> filterString(List<String> list, Predicate<String> predicate) {
        List<String> result = new ArrayList<>();
        for (String str : list) {
            if (predicate.test(str)) {
                result.add(str);
            }
        }
        return result;
    }
}

通过上面的事例,我的理解函数式接口似乎和匿名内部类,和lambda表达式是一个东西。如果更清晰概括的读者,可以在评论区留下你的理解和概括。

其他函数接口

函数式接口参数类型返回参数使用场景
BiFunction(T, U, R)T, UR对类型为 T,U 的参数应用操作,返回 R 类型的结果。接口定义的方法:R apply(T t, U u)
UnaryOperatorTT对类型为 T 的对象进行一 元运算, 并返回 T 类型的 结果。 包含方法为 T apply(T t)
BinaryOperatorT, TT对类型为 T 的对象进行二 元运算, 并返回 T 类型的 结果。 包含方法为T apply(T t1, T t2)
BiConsumer<T, U>T, Uvoid对类型为 T, U 参数应用 操作。 包含方法为 void accept(T t, U u)
ToIntFunctionTint计算 int 值的函数
ToLongFunctionTlong计算 long 值的函数
ToDoubleFunctionTdouble计算 double 值的函数
IntFunctionintR参数为 int 类型的函数
LongFunctionlongR参数为 long 类型的函数
DoubleFunctiondoubleR参数为 double 类型的函数

总结

? 通过使用函数式接口,可以将Lambda表达式作为参数传递给方法,从而简化代码,提高代码的可读性和维护性,当然这种简洁性和可读性是仁者见仁,智者见智的事情。

文章来源:https://blog.csdn.net/weixin_50087960/article/details/135485062
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。