Java8 函數(shù)式接口 學(xué)習(xí)筆記

一, 函數(shù)式編程

java中的函數(shù)式編程體現(xiàn)就是Lambda和方法引用:

Lambda

// 1.1使用匿名內(nèi)部類  
new Thread(new Runnable() {  
    @Override  
    public void run() {  
        System.out.println("Hello world !");  
    }  
}).start();  
  
// 1.2使用 lambda 獲得Runnable接口對象  
new Thread(() -> System.out.println("Hello world !")).start();

Lambda除了簡潔之外造成,還具有延遲執(zhí)行特點(diǎn)

延遲執(zhí)行

有些場景的代碼執(zhí)行后,結(jié)果不一定會被使用雄嚣,從而造成性能浪費(fèi)晒屎。而Lambda表達(dá)式是延遲執(zhí)行的,這正好可以作為解決方案缓升,提升性能鼓鲁。

public class Demo01Logger {
    private static void log(int level, String msg) {
        if (level == 1) {
            System.out.println(msg);
        }
     }
    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";
        log(2, msgA + msgB + msgC);//級別1 不一定能夠滿足 但是 字符串連接操作還是執(zhí)行了 那么字符串的拼接操作就白做了,存在性能浪費(fèi)
    }
}

Lambda的更優(yōu)寫法:

@FunctionalInterface
public interface MessageBuilder {
    String buildMessage();
}
public class Demo02LoggerLambda {
    private static void log(int level, MessageBuilder builder) {
        if (level == 1) {
            System.out.println(builder.buildMessage());// 實(shí)際上利用內(nèi)部類 延遲的原理,代碼不相關(guān) 無需進(jìn)入到啟動(dòng)代理執(zhí)行
        }
    }
    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";
       log(2,()->{
                System.out.println("lambda 是否執(zhí)行了");
                return msgA + msgB + msgC;
        });
    }
}

方法引用

方法引用港谊,不是方法調(diào)用骇吭!
方法引用是 lambda 表達(dá)式的語法糖,任何用方法引用的地方都可由lambda表達(dá)式替換

list.forEach(value -> System.out.println(value));

可替換為

list.forEach(System.out::println);
類別 使用形式
靜態(tài)方法引用 類名 :: 靜態(tài)方法名
實(shí)例方法引用 對象名(引用名) :: 實(shí)例方法名
類方法引用 類名 :: 實(shí)例方法名
構(gòu)造方法引用 類名 :: new

二歧寺, 函數(shù)式接口

定義:函數(shù)式接口(Functional Interface):有且僅有一個(gè)抽象方法的接口燥狰,但可以有多個(gè)非抽象方法的接口

  • 你可以通過 Lambda 表達(dá)式或方法引用來創(chuàng)建該接口的對象。
  • 可以在任意函數(shù)式接口上使用 @FunctionalInterface 注解斜筐,這樣做可以檢測它是否是一個(gè)函數(shù)式接口

@FunctionalInterface

在JDK 8中引入了FunctionalInterface接口龙致,其源代碼定義如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

加上@FunctionalInterface標(biāo)注,則會觸發(fā)JavaCompiler的檢查。對于符合函數(shù)接口的接口顷链,加不加都無關(guān)緊要目代,但是加上則會提供一層編譯檢查的保障。如果不符合,則會報(bào)錯(cuò)像啼。

需要注意的是:接口中只能存在一個(gè)抽象方法
格式:

修飾符 interface 接口名稱{
    public abstract 返回值 方法名稱(參數(shù)列表)
    // 其他方式 
}
// public abstract 可以不寫 編譯器自動(dòng)加上
修飾符 interface 接口名稱{
       返回值 方法名稱(參數(shù)列表)
    // 其他方式 
}

調(diào)用舉例:

@FunctionalInterface // 標(biāo)明為函數(shù)式接口
public abstract MyFunctionInterface{
    void method(); //抽象方法
}

public class TestFunctional {
    // 定義一個(gè)含有函數(shù)式接口的方法
    public static void doSomething(MyFunctionInterface functionalInterface) {
        functionalInterface.method();//調(diào)用自定義函數(shù)式接口的方法
    }
    public static void main(String[] args) {
        //調(diào)用函數(shù)式接口的方法
        MyFunctionInterface functionalInterface = () -> System.out.println("hello!")
        doSomething(functionalInterface );
    }
}

常用函數(shù)式接口

接口 參數(shù) 返回值 說明
Supplier<T> T 供給型俘闯;無參,返回一個(gè)指定泛型的對象
Consumer<T> T 消費(fèi)型忽冻;傳入一個(gè)指定泛型的參數(shù)真朗,無返回值
Predicate<T> T Boolean 斷言型;判斷函數(shù)僧诚,返回判斷結(jié)果true/false
Function<T,R> T R 方法型遮婶;輸入一個(gè)參數(shù),得到一個(gè)結(jié)果

Supplier

無參有返回值

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

使用:

public class TestSupplier {
    public static void main(String[] args) {
         // 產(chǎn)生的數(shù)據(jù)作為 sout 作為輸出
        Supplier<String> supply = ()->"產(chǎn)生數(shù)據(jù)"
        System.out.println(supply.get());//輸出“產(chǎn)生數(shù)據(jù)”
    }
}

Consumer

有參無返回值

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
    ...
}

使用:

public class TestComsumer {
    public static void main(String[] args) {
        Consumer<String> consumer = s->System.out.println(s)
        consumer.accept("hello");//輸出“hello”
    }
}

Predicate

對入?yún)?shù)據(jù)進(jìn)行判斷湖笨,并返回boolean

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
    ...
}

使用:

public class UsePredicate {
    public static void main(String[] args) {
        Predicate<Integer> predicate = (x)-> x==10;
        System.out.println(predicate.test(10));//輸出true
    }
}

Function

將入?yún)轉(zhuǎn)為返回值R

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

使用:

// 將數(shù)字轉(zhuǎn)換為String類型
private static void numberToString() {
    String apply = function.apply(12);
    System.out.println("轉(zhuǎn)換結(jié)果:"+apply);
}
public static void main(String[] args) {
        Function<Number, String> function = (s)->String.valueOf(s)
    System.out.println("轉(zhuǎn)換結(jié)果:"+function.apply(12));//輸出“12”
}

三旗扑, Functional Java

Functional Java是一個(gè)第三方庫,是一個(gè)在Java語言中實(shí)現(xiàn)函數(shù)型編程范式的類庫慈省。

標(biāo)準(zhǔn)的Java 8 也引入了很多函數(shù)型編程范式的元素臀防,比如Stream,lambda以及函數(shù)型接口边败。但在功能上Java 8 遠(yuǎn)不如Functional Java豐富袱衷,使用上也受到一定的限制。

Functional 項(xiàng)目地址:https://github.com/functionaljava/functionaljava

引入

//主包
compile "org.functionaljava:functionaljava:4.8"
//可以不引入
compile "org.functionaljava:functionaljava-java8:4.8"
compile "org.functionaljava:functionaljava-quickcheck:4.8"
compile "org.functionaljava:functionaljava-java-core:4.8"

F0, F, F2, …, F8

對應(yīng)Fuction<T,R>類笑窜, F<A, B>輸入類型為A致燥,返回值類型為B
F0沒有入?yún)ⅲ現(xiàn)有1個(gè)入?yún)⑴沤兀釉椋現(xiàn)8有8個(gè)入?yún)?br> 返回值類型都只有一個(gè),最后那個(gè)類型參數(shù)代表返回值類型断傲。

F<Integer, Integer> twice = n -> n * 2;
F2<Integer, Integer, Integer> f = (a, b) -> a + b;
F3<Integer, Integer, Integer, Integer> g = (a, b, c) -> a + b + c;

Effect0, Effect1, Effect2, …, Effect8

沒有返回值的函數(shù)接口類型, 對應(yīng)Consumer
Effect0沒有入?yún)⑼阎ǎ珽ffect1有1個(gè)入?yún)ⅲ险郑珽ffect8有8個(gè)入?yún)?/p>

Effect1<Integer> abc = n -> System.out.println(n);
FJ 接口 FJ 方法 Java 8 接口 Java 8 方法
Effect2<T, U> f BiConsumer<T, U> accept
F2<T, U, R> f BiFunction<T, U, R> apply
F2<T, T, T> f BinaryOperator<T> apply
F2<T, U, Boolean> f BiPredicate<T, U> test
F0<Boolean> f BooleanSupplier getAsBoolean

其他特性不多做介紹了急凰。。猜年。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末抡锈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乔外,更是在濱河造成了極大的恐慌床三,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杨幼,死亡現(xiàn)場離奇詭異撇簿,居然都是意外死亡聂渊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門四瘫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汉嗽,“玉大人,你說我怎么就攤上這事找蜜”睿” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵洗做,是天一觀的道長弓叛。 經(jīng)常有香客問我,道長诚纸,這世上最難降的妖魔是什么撰筷? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮畦徘,結(jié)果婚禮上毕籽,老公的妹妹穿的比我還像新娘。我一直安慰自己井辆,他們只是感情好影钉,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著掘剪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奈虾。 梳的紋絲不亂的頭發(fā)上夺谁,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機(jī)與錄音肉微,去河邊找鬼匾鸥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛碉纳,可吹牛的內(nèi)容都是我干的勿负。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼劳曹,長吁一口氣:“原來是場噩夢啊……” “哼奴愉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起铁孵,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤锭硼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蜕劝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體檀头,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡轰异,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了暑始。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搭独。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖廊镜,靈堂內(nèi)的尸體忽然破棺而出牙肝,到底是詐尸還是另有隱情,我是刑警寧澤期升,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布惊奇,位于F島的核電站,受9級特大地震影響播赁,放射性物質(zhì)發(fā)生泄漏颂郎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一容为、第九天 我趴在偏房一處隱蔽的房頂上張望乓序。 院中可真熱鬧,春花似錦坎背、人聲如沸替劈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陨献。三九已至,卻和暖如春懂更,著一層夾襖步出監(jiān)牢的瞬間眨业,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工沮协, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留龄捡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓慷暂,卻偏偏與公主長得像聘殖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子行瑞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

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