java8函数式接口(Functional Interface),一篇抠脚都能懂的入门文章

介绍

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

函数式接口可以被隐式转换为 lambda 表达式(箭头函数)。

函数式接口代表的一种契约, 一种对某个特定函数类型的契约。
Lambda表达式不能脱离上下文而存在,它必须要有一个明确的目标类型(interface),而这个目标类型就是某个函数式接口。

java8之前已经存在的函数式接口有很多,比如java.lang.Runnable、java.util.concurrent.Callable、java.util.Comparator等。
而新增加的函数式接口都在java.util.function包下。

Java 不会强制要求你使用 @FunctionalInterface 注解来标记你的接口是函数式接口, 然而,作为API作者, 你可能倾向使用@FunctionalInterface指明特定的接口为函数式接口, 这只是一个设计上的考虑, 可以让用户很明显的知道一个接口是函数式接口。

入门

先来看一个入门的例子就能明白为啥函数式接口是一种契约:

@FunctionalInterface
public interface Predicate<T> {
    //该接口有一个抽象方法test,它接受一个参数t,并且返回boolean
    //如此定义一个抽象方法,就是在约定,我这个抽象方法的实现类,一定是仅有一个参数,并且只会返回一个boolean的值。
    //所以说函数式接口是一种契约。
    boolean test(T t);
}

Predicate的使用实例:

//方法evel接受一个列表和一个Predicate接口
//list每个元素会当成 predicate的test方法的参数。
//因为函数式接口是可以使用Lambda表达式的,所以第二个参数这里就可以使用箭头函数了。
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
      //循环list
      for(Integer i: list) {
         //调用predicate的test方法,返回一个boolean值。
         if(predicate.test(i)) {
            System.out.println(i + " ");
         }
          //疑问:Predicate是一个接口啊!那他具体执行的方法(实现类/实现方法)在哪里呢????
          //请看main方法!!!
      }
   }
   
public static void main(String args[]){
      //定义一个list
      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

      //n -> n%2   
      //其实很简单,这个Lambda表达式其实就是Predicate接口的实现:
      //  箭头左边 n 是一个参数, 它会被传递到 Predicate 接口的 test 方法中
      //  而箭头右边 n%2 其实就是这个 test 抽象方法的实现方法,它用来计算输入参数是否是一个偶数。
      //所以整个方法就是用来打印list中的偶数了。
      eval(list, n-> n%2 == 0 );
      System.out.println("输出所有偶数:");

   }

新函数式接口

java.util.function中定义了几组类型的函数式接口以及针对基本数据类型的子接口。

  • Predicate -- 传入一个参数,返回一个bool结果, 方法为boolean test(T t)
  • Consumer -- 传入一个参数,无返回值,纯消费。 方法为void accept(T t)
  • Function -- 传入一个参数,返回一个结果,方法为R apply(T t)
  • Supplier -- 无参数传入,返回一个结果,方法为T get()
  • UnaryOperator -- 一元操作符, 继承Function,传入参数的类型和返回类型相同。
  • BinaryOperator -- 二元操作符, 传入的两个参数的类型和返回类型相同, 继承BiFunction

函数式接口中的抽象方法

在上面介绍中,说到函数式接口有且仅有一个抽象方法,其实是不正确的,因为函数式接口中可以额外定义多个抽象方法,但这些抽象方法签名必须和Object类的 public 方法一样,只是我们一般不会再重新定义这些方法。

@FunctionalInterface
public interface ObjectMethodFunctionalInterface {
	void count(int i);
	
	String toString(); //same to Object.toString
	int hashCode(); //same to Object.hashCode
	boolean equals(Object obj); //same to Object.equals
}

声明异常

函数式接口的抽象方法可以声明 可检查异常(checked exception)。 在调用目标对象的这个方法时必须catch这个异常。

@FunctionalInterface
interface InterfaceWithException {
	//声明异常
	void apply(int i) throws Exception;
}

捕获异常:

public class FunctionalInterfaceWithException {
	public static void main(String[] args) {
		InterfaceWithException target = i -> {};
		try {
			target.apply(10);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

非法抛出异常:

@FunctionalInterface
interface InterfaceWithException {
	//没有声明异常
	void apply(int i);
}
public class FunctionalInterfaceWithException {
	public static void main(String[] args) {
		//函数式接口没有声明异常,
		//而 Lambda中却抛出了异常,此时是无法通过编译的!!!
		InterfaceWithException target = i -> {throw new Exception();};
	}
}
 

静态方法

函数式接口中除了那个抽象方法外还可以包含静态方法。
Java 8以前的规范中接口中不允许定义静态方法。 静态方法只能在类中定义。 但是到了Java 8,可以定义静态方法。

默认方法

Java 8中允许接口实现方法, 而不是简单的声明, 这些方法叫做默认方法,使用特殊的关键字default。
因为默认方法不是抽象方法,所以不影响我们判断一个接口是否是函数式接口。

function包中的类的函数式接口概览

  1. BiConsumer<T,U> 代表了一个接受两个输入参数的操作,并且不返回任何结果

  2. BiFunction<T,U,R> 代表了一个接受两个输入参数的方法,并且返回一个结果

  3. BinaryOperator<T> 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果

  4. BiPredicate<T,U> 代表了一个两个参数的boolean值方法

  5. BooleanSupplier 代表了boolean值结果的提供方

  6. Consumer<T> 代表了接受一个输入参数并且无返回的操作

  7. DoubleBinaryOperator 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。

  8. DoubleConsumer 代表一个接受double值参数的操作,并且不返回结果。

  9. DoubleFunction<R> 代表接受一个double值参数的方法,并且返回结果

  10. DoublePredicate 代表一个拥有double值参数的boolean值方法

  11. DoubleSupplier 代表一个double值结构的提供方

  12. DoubleToIntFunction 接受一个double类型输入,返回一个int类型结果。

  13. DoubleToLongFunction 接受一个double类型输入,返回一个long类型结果

  14. DoubleUnaryOperator 接受一个参数同为类型double,返回值类型也为double 。

  15. Function<T,R> 接受一个输入参数,返回一个结果。

  16. IntBinaryOperator 接受两个参数同为类型int,返回值类型也为int 。

  17. IntConsumer 接受一个int类型的输入参数,无返回值 。

  18. IntFunction<R> 接受一个int类型输入参数,返回一个结果 。

  19. IntPredicate :接受一个int输入参数,返回一个布尔值的结果。

  20. IntSupplier 无参数,返回一个int类型结果。

  21. IntToDoubleFunction 接受一个int类型输入,返回一个double类型结果 。

  22. IntToLongFunction 接受一个int类型输入,返回一个long类型结果。

  23. IntUnaryOperator 接受一个参数同为类型int,返回值类型也为int 。

  24. LongBinaryOperator 接受两个参数同为类型long,返回值类型也为long。

  25. LongConsumer 接受一个long类型的输入参数,无返回值。

  26. LongFunction<R> 接受一个long类型输入参数,返回一个结果。

  27. LongPredicate R接受一个long输入参数,返回一个布尔值类型结果。

  28. LongSupplier 无参数,返回一个结果long类型的值。

  29. LongToDoubleFunction 接受一个long类型输入,返回一个double类型结果。

  30. LongToIntFunction 接受一个long类型输入,返回一个int类型结果。

  31. LongUnaryOperator 接受一个参数同为类型long,返回值类型也为long。

  32. ObjDoubleConsumer<T> 接受一个object类型和一个double类型的输入参数,无返回值。

  33. ObjIntConsumer<T> 接受一个object类型和一个int类型的输入参数,无返回值。

  34. ObjLongConsumer<T> 接受一个object类型和一个long类型的输入参数,无返回值。

  35. Predicate<T> 接受一个输入参数,返回一个布尔值结果。

  36. Supplier<T> 无参数,返回一个结果。

  37. ToDoubleBiFunction<T,U> 接受两个输入参数,返回一个double类型结果

  38. ToDoubleFunction<T> 接受一个输入参数,返回一个double类型结果

  39. ToIntBiFunction<T,U> 接受两个输入参数,返回一个int类型结果。

  40. ToIntFunction<T> 接受一个输入参数,返回一个int类型结果。

  41. ToLongBiFunction<T,U> 接受两个输入参数,返回一个long类型结果。

  42. ToLongFunction<T> 接受一个输入参数,返回一个long类型结果。

  43. UnaryOperator<T> 接受一个参数为类型T,返回值类型也为T。

本文大量参考鸟窝哥,原文请移步:https://colobu.com/2014/10/28/secrets-of-java-8-functional-interface/#@FunctionalInterface

转载于:https://my.oschina.net/u/3244997/blog/3014977

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值