在Java中有许多已有的接口都须要封装代码块,例如:Runnable或者Comparator。lambda表达式与这些接口是向后兼容的。对于只包含一个抽象方法的接口,你能够经过lambda表达式来建立该接口的对象,这种接口被称为函数式接口。注意:Java8中接口能够声明非抽象的方法。java
为了演示函数式接口转换,咱们以Arrays.sort方法为例。该方法的第二个参数须要一个Comparator接口(该接口只含有一个方法)的实例。接下来咱们编写一个简单的lambda表达式:编程
Arrays.sort(words,(first,second) -> Integer.compare(first.length(),second.length()));
在这个表达式背后,Arrays.sort方法会接收一个实现了Comparaotr<String>接口的类的实例。调用该对象的compare方法会执行lambda表达式中的代码。这些对象和类的管理彻底依赖于如何实现,所以比传统的内部类效率更高。你最好将一个lambda表达式想象成一个函数,而不是一个对象,并记住它能够被转换为一个函数式接口。编程语言
事实上,函数式接口的转换是你在java中使用lambda表达式能作的惟一一件事。在其余支持函数文本的编程语言中,你能够声明像(String,String) -> int这样的函数类型,声明这种类型的变量,并使用这些变量来保存函数表达式。可是,java设计者们仍是决定坚持使用熟悉的接口概念,而没有将函数类型添加到java中。函数式编程
Java API在java.util.function包中定义了许多很是通用的函数式接口(后面blog会进行详细讲解)。其中接口BiFunction<T,U,R>描述了T和U类型的方法参数以及返回类型R。你能够将咱们的字符串比较lambda表达式保存在一个该类型的变量中:函数
BiFunction<String,String,Integer> comp = (first,second) -> Integer.compare(first.length(),second.length());
可是,这对排序并不能起到什么帮助做用。不存在接收BiFunction做为参数的Arrays.sort方法。若是你以前使用过其余函数式编程语言,你可能会对此感到奇怪。可是对于Java开发人员来讲,这再天然不过了。像Comparator这样的接口有着特定的目的,而不单单是一个接收参数和返回类型的方法。Java8保留了这一习惯。当你但愿使用lambda表达式时,你仍然要牢记表达式的目的,并为它指定一个函数式接口。spa
如今java8自己的API使用了java.util.function中的接口,未来这些接口极可能被应用在各个地方。可是请记住,任何一个lambda表达式均可以等价转换成如今所使用的API中对应的函数式接口。设计
注意:你能够在任意函数式接口上标注@FunctionalInterface注解,这样作有两个好处。首先,编译器会检查标注该注解的实体,检查它是不是只包含一个抽象方法的接口。另外,在javadoc页面也会包含一条声明,说明这个接口是一个函数式接口。该注解并不要求强制使用。从概念上来说,全部只含有一个抽象方法的接口都是函数式接口,可是使用@FunctionalInterface注解会让你代码看上去更清楚。code
最后,当一个lambda表达式被转换为一个函数式接口的实例时,请注意处理检查期异常。若是lambda表达式中可能会抛出一个检查期异常,那么该异常须要在目标接口的抽象方法中进行声明。例如,如下表达式会产生一个错误:对象
//错误:Thread.sleep能够抛出一个检查期的InterruptedException Runnable sleeper = () -> {System.out.println("Zzz");Thread.sleep(1000);};
因为Runnable.run不能抛出任何异常,因此这个赋值是不合法的。有两种方法能够修正该问题。一种是在lambda表达式中捕获异常,另外一种是将lambda表达式赋值给一个其抽象方法能够抛出异常的接口。例如,Callable接口的call方法能够抛出任何异常。
blog