函數(shù)式接口挽霉、默認(rèn)方法和Optional類(lèi)
函數(shù)式接口
函數(shù)式接口通過(guò)一個(gè)單一的功能來(lái)表現(xiàn)防嗡。例如,帶有單個(gè)compareTo方法的比較接口侠坎,被用于比較的場(chǎng)合蚁趁。Java 8 開(kāi)始定義了大量的函數(shù)式接口來(lái)廣泛地用于lambda表達(dá)式。
Java 8 引入的一個(gè)核心概念是函數(shù)式接口(Functional Interfaces)实胸。通過(guò)在接口里面添加一個(gè)抽象方法他嫡,這些方法可以直接從接口中運(yùn)行。如果一個(gè)接口定義唯一一個(gè)抽象方法庐完,那么這個(gè)接口就成為函數(shù)式接口涮瞻。同時(shí),引入了一個(gè)新的注解:@FunctionalInterface假褪∈鹧剩可以把他它放在一個(gè)接口前,表示這個(gè)接口是一個(gè)函數(shù)式接口。這個(gè)注解是非必須的宁否,只要接口只包含一個(gè)方法的接口窒升,虛擬機(jī)會(huì)自動(dòng)判斷,不過(guò)最好在接口上使用注解 @FunctionalInterface 進(jìn)行聲明慕匠。在接口中添加了 @FunctionalInterface 的接口饱须,只允許有一個(gè)抽象方法,否則編譯器也會(huì)報(bào)錯(cuò)台谊。引用自IBM - Java 8 新特性概述
相關(guān)的接口及描述
下面是部分函數(shù)式接口的列表
接口 | 描述 |
---|---|
BitConsumer<T,U> | 改接口代表了接收兩個(gè)輸入?yún)?shù)T蓉媳、U,并且沒(méi)有返回的操作 |
BiFunction<T,U,R> | 該接口代表提供接收兩個(gè)參數(shù)T锅铅、U酪呻,并且產(chǎn)生一個(gè)結(jié)果R的方法 |
BinaryOperator<T> | 代表了基于兩個(gè)相同類(lèi)型的操作數(shù), 產(chǎn)生任然是相同類(lèi)型結(jié)果的操作 |
BiPredicate<T,U> | 代表了對(duì)兩個(gè)參數(shù)的斷言操作(基于Boolean值的方法) |
BooleanSupplier | 代表了一個(gè)給出Boolean值結(jié)果的方法 |
Consumer<T> | 代表了接受單一輸入?yún)?shù)并且沒(méi)有返回值的操作 |
DoubleBinaryOperator | 代表了基于兩個(gè)Double類(lèi)型操作數(shù)的操作,并且返回一個(gè)Double類(lèi)型的返回值 |
DoubleConsumer | 代表了一個(gè)接受單個(gè)Double類(lèi)型的參數(shù)并且沒(méi)有返回的操作 |
DoubleFunction<R> | 代表了一個(gè)接受Double類(lèi)型參數(shù)并且返回結(jié)果的方法 |
DoublePredicate | 代表了對(duì)一個(gè)Double類(lèi)型的參數(shù)的斷言操作 |
DoubleSupplier | 代表了一個(gè)給出Double類(lèi)型值的方法 |
DoubleToIntFunction | 代表了接受單個(gè)Double類(lèi)型參數(shù)但返回Int類(lèi)型結(jié)果的方法 |
DoubleToLongFunction | 代表了接受單個(gè)Double類(lèi)型參數(shù)但返回Long類(lèi)型結(jié)果的方法 |
DoubleUnaryOperator | 代表了基于單個(gè)Double類(lèi)型操作數(shù)且產(chǎn)生Double類(lèi)型結(jié)果的操作 |
Function<T,R> | 代表了接受一個(gè)參數(shù)并且產(chǎn)生一個(gè)結(jié)果的方法 |
IntBinaryOperator | 代表了對(duì)兩個(gè)Int類(lèi)型操作數(shù)的操作盐须,并且產(chǎn)生一個(gè)Int類(lèi)型的結(jié)果 |
IntConsumer | 代表了接受單個(gè)Int類(lèi)型參數(shù)的操作玩荠,沒(méi)有返回結(jié)果 |
IntFunction<R> | 代表了接受Int類(lèi)型參數(shù)并且給出返回值的方法 |
IntPredicate | 代表了對(duì)單個(gè)Int類(lèi)型參數(shù)的斷言操作 |
更多的接口可以參考Java官方API手冊(cè):java.lang.Annotation Type FunctionalInterface。在實(shí)際使用過(guò)程中贼邓,加有 @FunctionalInterface 注解的方法均是此類(lèi)接口阶冈,位于java.util.Funtion包中。
一個(gè)函數(shù)式編程的例子
下面我們通過(guò)一個(gè)例子學(xué)習(xí)如何使用這些函數(shù)式編程的接口
新建一個(gè)類(lèi) NewFeaturesTester.java塑径,以下是 NewFeaturesTester.java 類(lèi)中應(yīng)當(dāng)輸入的代碼:
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class NewFeaturesTester {
public static void main(String args[]){
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println("All of the numbers:");
eval(list, n->true);
System.out.println("Even numbers:");
eval(list, n-> n%2 == 0 );
System.out.println("Numbers that greater than 5:");
eval(list, n -> n > 5 );
}
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
for(Integer n: list) {
if(predicate.test(n)) {
System.out.println(n);
}
}
}
}
默認(rèn)方法
Java 8在接口方面引入了一個(gè)關(guān)于默認(rèn)方法實(shí)現(xiàn)的新概念女坑。它也是作為一種向后兼容能力而出現(xiàn),舊的接口也能用到Lambda表達(dá)式中统舀。例如匆骗,List或 Collection 接口是沒(méi)有forEach方法的聲明的。但是绑咱,通過(guò)這些默認(rèn)方法能夠就能輕易地打破集合框架實(shí)現(xiàn)的限制绰筛。Java 8引入默認(rèn)方式使得 List 和 Collection 接口能夠擁有 forEach 方法的默認(rèn)實(shí)現(xiàn)枢泰。實(shí)現(xiàn)了這些接口的類(lèi)也不必再實(shí)現(xiàn)相同的功能了描融。
語(yǔ)法如下所示:
本段代碼是示例代碼,僅供理解使用。
public interface boy {
default void print(){
System.out.println("I am a boy");
}
}
多個(gè)默認(rèn)值
接口中有了默認(rèn)方法之后衡蚂,在同一個(gè)類(lèi)里面實(shí)現(xiàn)兩個(gè)帶有相同默認(rèn)方法的接口就可行了窿克。
下面的代碼演示了如何解決這種含糊不清的情況。
首先是同一個(gè)類(lèi)里面的兩個(gè)接口
本段是示例代碼毛甲,僅供理解
public interface younger {
default void print(){
System.out.println("I am a younger.");
}
}
public interface learner {
default void print(){
System.out.println("I am a learner.");
}
}
第一個(gè)解決辦法就是創(chuàng)建一個(gè)自有的辦法年叮,來(lái)重寫(xiě)默認(rèn)的實(shí)現(xiàn)。就像這樣:
本段代碼是示例代碼玻募,僅供理解使用只损。
public class student implements younger, learner {
public void print(){
System.out.println("I am a younger and a learner, so I am a student.");
}
}
另一個(gè)解決辦法就是使用超類(lèi) super 來(lái)調(diào)用特定接口的默認(rèn)方法。
本段代碼是示例代碼,僅供理解使用
public class student implements younger, learner {
public void print(){
learner.super.print();
}
}
靜態(tài)默認(rèn)方法
你也可以為這個(gè)接口增加靜態(tài)的輔助方法(helper), 就像下面這樣:
本段代碼是示例代碼跃惫,僅供理解使用
public interface Younger {
default void print(){
System.out.println("I am a younger.");
}
static void sayHi(){
System.out.println("Young is the capital.");
}
}
一個(gè)默認(rèn)方法的例子
下面我們通過(guò)一個(gè)例子來(lái)掌握如何使用默認(rèn)方法叮叹。請(qǐng)看下面的代碼
public class NewFeaturesTester {
public static void main(String args[]) {
Younger younger = new Student();
younger.print();
}
}
interface Younger {
default void print() {
System.out.println("I am a younger.");
}
static void sayHi() {
System.out.println("Young is the capital.");
}
}
interface Learner {
default void print() {
System.out.println("I am a learner.");
}
}
class Student implements Younger, Learner {
public void print() {
Younger.super.print();
Learner.super.print();
Younger.sayHi();
System.out.println("I am a student!");
}
}
Optional 類(lèi)
Optional是一個(gè)容器對(duì)象,用于容納非空對(duì)象爆存。Optional對(duì)象通過(guò)缺失值值代表null蛉顽。這個(gè)類(lèi)有許多實(shí)用的方法來(lái)促使代碼能夠處理一些像可用或者不可用的值,而不是檢查那些空值(null)先较。Java 8中引入的這個(gè)特性有點(diǎn)像Google Guava里的Optional(Guava 是一個(gè) Google 的基于Java 6的類(lèi)庫(kù)集合的擴(kuò)展項(xiàng)目)携冤。
在Java官方文檔的解釋中,它是一個(gè)可以為null的容器對(duì)象闲勺。如果值存在則 isPresent() 方法會(huì)返回 true 曾棕,調(diào)用 get()方法會(huì)返回該對(duì)象。
類(lèi)的聲明及方法
下面是java.util.Optional<T>類(lèi)的聲明:
public final class Optional<T>
extends Object
這個(gè)類(lèi)繼承了java.lang.Object類(lèi)大多數(shù)方法霉翔。主要有:
接口 | 描述 |
---|---|
static <T> Optional<T> empty() | 該方法返回一個(gè)空的Optional實(shí)例 |
boolean equals(Object obj) | 該方法可以指示某個(gè)對(duì)象是否與當(dāng)前Optional對(duì)象相等 |
Optional<T> filter(Predicate<? super <T> predicate) | 如果一個(gè)值存在并且這個(gè)值滿足某個(gè)給定的斷言睁蕾,那么該方法將返回一個(gè)描述該值的Optional對(duì)象;否則债朵,將返回一個(gè)空的Optional對(duì)象 |
Optional flatMap(Function<? super T,Optional> mapper) | 如果一個(gè)值存在子眶,該方法會(huì)把一個(gè)map方法應(yīng)用于它,并且返回結(jié)果序芦;否則臭杰,將返回空的Optional對(duì)象 |
T get() | 如果一個(gè)值存在于當(dāng)前Optional中,則返回這個(gè)值谚中;否則將拋出一個(gè)NoSuchElementException異常 |
int hashCode() | 返回當(dāng)前值的hash編碼值渴杆。若這個(gè)值不存在,則返回0 |
void ifPresent(Consumer<? super T> consumer) | 如果一個(gè)值存在宪塔,該方法會(huì)通過(guò)該值調(diào)用指定的consumer磁奖。如果不存在,則不調(diào)用 |
boolean isPresent() | 返回一個(gè)值是否存在 |
Optional map(Function<? super T,? extends U> mapper | 如果一個(gè)值存在某筐,則將某個(gè)map方法應(yīng)用于它比搭。如果這個(gè)值是非空的,則返回一個(gè)描述結(jié)果的Optional對(duì)象 |
static <T> Optional<T> of(T value) | 返回某個(gè)存在的非空值的Optional對(duì)象 |
更多的你可以訪問(wèn)官方API手冊(cè)查看:http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
一個(gè)Optional類(lèi)的例子
import java.util.Optional;
public class NewFeaturesTester {
public static void main(String args[]){
NewFeaturesTester tester = new NewFeaturesTester();
Integer value1 = null;
Integer value2 = new Integer(5);
// ofNullable 允許傳參時(shí)給出 null
Optional<Integer> a = Optional.ofNullable(value1);
// 如果傳遞的參數(shù)為null南誊,那么 of 將拋出空指針異常(NullPointerException)
Optional<Integer> b = Optional.of(value2);
System.out.println(tester.sum(a,b));
}
public Integer sum(Optional<Integer> a, Optional<Integer> b){
// isPresent 用于檢查值是否存在
System.out.println("First parameter is present: " + a.isPresent());
System.out.println("Second parameter is present: " + b.isPresent());
// 如果當(dāng)前返回的是傳入的默認(rèn)值身诺,orElse 將返回它
Integer value1 = a.orElse(new Integer(0));
// get 用于獲得值,條件是這個(gè)值必須存在
Integer value2 = b.get();
return value1 + value2;
}
}