函數(shù)式接口、默認(rèn)方法和Optional類(lèi)

函數(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á)式中统舀。例如匆骗,ListCollection 接口是沒(méi)有forEach方法的聲明的。但是绑咱,通過(guò)這些默認(rèn)方法能夠就能輕易地打破集合框架實(shí)現(xiàn)的限制绰筛。Java 8引入默認(rèn)方式使得 ListCollection 接口能夠擁有 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;
   }
}

擴(kuò)展閱讀

Java 8 Optional類(lèi)深度解析

參考鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抄囚,一起剝皮案震驚了整個(gè)濱河市霉赡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌幔托,老刑警劉巖穴亏,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嗓化,警方通過(guò)查閱死者的電腦和手機(jī)锅劝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蟆湖,“玉大人故爵,你說(shuō)我怎么就攤上這事∮缃颍” “怎么了诬垂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)伦仍。 經(jīng)常有香客問(wèn)我结窘,道長(zhǎng),這世上最難降的妖魔是什么充蓝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任隧枫,我火速辦了婚禮,結(jié)果婚禮上谓苟,老公的妹妹穿的比我還像新娘官脓。我一直安慰自己,他們只是感情好涝焙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布卑笨。 她就那樣靜靜地躺著,像睡著了一般仑撞。 火紅的嫁衣襯著肌膚如雪赤兴。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天隧哮,我揣著相機(jī)與錄音桶良,去河邊找鬼。 笑死沮翔,一個(gè)胖子當(dāng)著我的面吹牛陨帆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鉴竭,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼歧譬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼岸浑!你這毒婦竟也來(lái)了搏存?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤矢洲,失蹤者是張志新(化名)和其女友劉穎璧眠,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡责静,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年袁滥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灾螃。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡题翻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出腰鬼,到底是詐尸還是另有隱情嵌赠,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布姜挺,位于F島的核電站彼硫,受9級(jí)特大地震影響拧篮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掖肋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望把篓。 院中可真熱鬧韧掩,春花似錦、人聲如沸坊谁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至翘瓮,卻和暖如春裤翩,著一層夾襖步出監(jiān)牢的瞬間踊赠,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荣赶,地道東北人鸽斟。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓剩燥,卻偏偏與公主長(zhǎng)得像立倍,于是被迫代替她去往敵國(guó)和親口注。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容