Java8新特性之函数式接口

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

/**
 * An informative annotation type used to indicate that an interface
 * type declaration is intended to be a functional interface 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
 * not 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.
 *
 * 

Note that instances of functional interfaces can be created with * lambda expressions, method references, or constructor references. * *

If a type is annotated with this annotation type, compilers are * required to generate an error message unless: * *

    *
  • The type is an interface type and not an annotation type, enum, or class. *
  • The annotated type satisfies the requirements of a functional interface. *
* *

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 operator) {
   Objects.requireNonNull(operator);
   final ListIterator li = this.listIterator();
   while (li.hasNext()) {
       li.set(operator.apply(li.next()));
   }
}

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

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

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

四大核心函数式接口

函数式接口 参数类型 返回参数 使用场景
Consumer 消费型接口 T void 对类型为 T 的对象应用操作,接口定义的方法:void accept(T t)
Supplier 供给型接口 T 返回类型为 T 的对象,接口定义的方法:T get()
Function函数式接口 T R 对类型为 T 的对象应用操作,并 R 类型的返回结果。接口定义的方法:R apply(T t)
Predicate 断言型接口 T boolean 确定类型为 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, U R 对类型为 T,U 的参数应用操作,返回 R 类型的结果。接口定义的方法:R apply(T t, U u)
UnaryOperator T T 对类型为 T 的对象进行一 元运算, 并返回 T 类型的 结果。 包含方法为 T apply(T t)
BinaryOperator T, T T 对类型为 T 的对象进行二 元运算, 并返回 T 类型的 结果。 包含方法为T apply(T t1, T t2)
BiConsumer T, U void 对类型为 T, U 参数应用 操作。 包含方法为 void accept(T t, U u)
ToIntFunction T int 计算 int 值的函数
ToLongFunction T long 计算 long 值的函数
ToDoubleFunction T double 计算 double 值的函数
IntFunction int R 参数为 int 类型的函数
LongFunction long R 参数为 long 类型的函数
DoubleFunction double R 参数为 double 类型的函数

总结

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

你可能感兴趣的:(Java新特性,python,开发语言)