摘要:利用前面所述的方法,這個例子可以用方法引用改寫成下面的樣子構(gòu)造函數(shù)引用對于一個現(xiàn)有構(gòu)造函數(shù),你可以利用它的名稱和關(guān)鍵字來創(chuàng)建它的一個引用。
第三章 Lambda表達(dá)式 函數(shù)式接口
函數(shù)式接口就是只定義一個抽象方法的接口,哪怕有很多默認(rèn)方法,只要接口只定義了一個抽象方法,它就仍然是一個函數(shù)式接口。常用函數(shù)式接口
函數(shù)描述符
函數(shù)式接口的抽象方法的簽名稱為函數(shù)描述符。在哪里可以使用Lambda?
@FunctionalInterface又是怎么回事只有在需要函數(shù)式接口的時候才可以傳遞Lambda
下哪些是使用Lambda表達(dá)式的有效方式?
(1)execute(() -> {}); public void execute(Runnable r){ r.run(); }(2)
return () -> "Tricky example ;-)";(3)
Predicatep = (Apple a) -> a.getWeight(); 答案:只有1和2是有效的。
第一個例子有效,是因為Lambda() -> {}具有簽名() -> void,這和Runnable中的
抽象方法run的簽名相匹配。請注意,此代碼運(yùn)行后什么都不會做,因為Lambda是空的!
第二個例子也是有效的。事實上,fetch方法的返回類型是Callable。
Callable基本上就定義了一個方法,簽名是() -> String,其中T被String代替
了。因為Lambda() -> "Trickyexample;-)"的簽名是() -> String,所以在這個上下文
中可以使用Lambda。
第三個例子無效,因為Lambda表達(dá)式(Apple a) -> a.getWeight()的簽名是(Apple) ->
Integer,這和Predicate:(Apple) -> boolean中定義的test方法的簽名不同。
這個標(biāo)注用于表示該接口會設(shè)計成一個函數(shù)式接口,@FunctionalInterface不是必需的,它就像是@Override標(biāo)注表示方法被重寫了。Java 7中的帶資源的try語句
函數(shù)式接口:Predicate斷言它已經(jīng)簡化了代碼,因為你不需要顯式地關(guān)閉資源了.
public static String processFile() throws IOException { try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) { return br.readLine(); } }
java.util.function.Predicate函數(shù)式接口:Consumer接口定義了一個名叫test的抽象方法,它接受泛型T對象,并返回一個boolean。
java.util.function.Consumer函數(shù)式接口:Function定義了一個名叫accept的抽象方法,它接受泛型T的對象,沒有返回(void)。
避免自動裝箱、拆箱java.util.function.Function
接口定義了一個叫作apply的方法,它接受一個泛型T的對象,并返回一個泛型R的對象。
eg:@FunctionalInterface public interface Function{ R apply(T t); } public static List map(List list, Function f) { List result = new ArrayList<>(); for(T s: list){ result.add(f.apply(s)); } return result; } // [7, 2, 6] List l = map( Arrays.asList("lambdas","in","action"), (String s) -> s.length() );
一般來說,針對專門的輸入?yún)?shù)類型的函數(shù)式接口的名稱都要加上對應(yīng)的原始類型前綴,比如DoublePredicate、IntConsumer、LongBinaryOperator、IntFunction等。Function接口還有針對輸出參數(shù)類型的變種:ToIntFunction關(guān)于異常、IntToDoubleFunction等。
請注意,任何庫中的函數(shù)式接口都不允許拋出受檢異常(checked exception)。如果你需要Lambda表達(dá)式來拋出異常,有兩種辦法:定義一個自己的函數(shù)式接口,并聲明受檢異常,或者把Lambda包在一個try/catch塊中。目標(biāo)類型
Lambda表達(dá)式需要的類型稱為目標(biāo)類型。(即對應(yīng)的函數(shù)式接口)類型推斷
方法引用你還可以進(jìn)一步簡化你的代碼。Java編譯器會從上下文(目標(biāo)類型)推斷出用什么函數(shù)式接
口來配合Lambda表達(dá)式,這意味著它也可以推斷出適合Lambda的簽名,因為函數(shù)描述符可以通
過目標(biāo)類型來得到。這樣做的好處在于,編譯器可以了解Lambda表達(dá)式的參數(shù)類型,這樣就可
以在Lambda語法中省去標(biāo)注參數(shù)類型。換句話說,Java編譯器會像下面這樣推斷Lambda的參數(shù)
類型:ListgreenApples = filter(inventory, a -> "green".equals(a.getColor()));
為三種不同類型的Lambda表達(dá)式構(gòu)建方法引用的辦法:
構(gòu)造函數(shù)引用Liststr = Arrays.asList("a","b","A","B"); str.sort((s1, s2) -> s1.compareToIgnoreCase(s2)); Lambda表達(dá)式的簽名與Comparator的函數(shù)描述符兼容。利用前面所述的方法,這個例子可
以用方法引用改寫成下面的樣子:Liststr = Arrays.asList("a","b","A","B"); str.sort(String::compareToIgnoreCase);
對于一個現(xiàn)有構(gòu)造函數(shù),你可以利用它的名稱和關(guān)鍵字new來創(chuàng)建它的一個引用:
ClassName::new。
Comparator 類內(nèi)部comparing實現(xiàn)構(gòu)造函數(shù)引用
要怎么樣才能對具有三個參數(shù)的構(gòu)造函數(shù),比如Color(int, int, int),使用構(gòu)造函數(shù)引用呢?
答案:你看,構(gòu)造函數(shù)引用的語法是ClassName::new,那么在這個例子里面就是Color::new。但是你需要與構(gòu)造函數(shù)引用的簽名匹配的函數(shù)式接口。但是語言本身并沒有提供這樣的函數(shù)式接口,你可以自己創(chuàng)建一個:public interface TriFunction{ R apply(T t, U u, V v); } 現(xiàn)在你可以像下面這樣使用構(gòu)造函數(shù)引用了:
TriFunctioncolorFactory = Color::new;
比較器復(fù)合comparing 方法一
查看 Comparator 類內(nèi)部實現(xiàn),還有一個 comparing 方法,實現(xiàn)如下,public static> Comparator comparing( Function super T, ? extends U> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); } 其返回值是 (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); 一個lambda表達(dá)式,也就是一個Compator
eg:Comparatorc = Comparator.comparing(Apple::getWeight); comparing 方法二
public staticComparator comparing( Function super T, ? extends U> keyExtractor, Comparator super U> keyComparator) { Objects.requireNonNull(keyExtractor); Objects.requireNonNull(keyComparator); return (Comparator & Serializable) (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), keyExtractor.apply(c2)); } 和comparing 方法一不同的是 該方法多了一個參數(shù) keyComparator ,keyComparator 是創(chuàng)建一個自定義的比較器。
Collections.sort(employees, Comparator.comparing( Employee::getName, (s1, s2) -> { return s2.compareTo(s1); }));
謂詞復(fù)合(斷言復(fù)合)逆序
inventory.sort(comparing(Apple::getWeight).reversed());比較器鏈
thenComparing方法就是做這個用的inventory.sort(comparing(Apple::getWeight) .reversed().thenComparing(Apple::getCountry));
函數(shù)復(fù)合謂詞接口包括三個方法:negate、and和or,讓你可以重用已有的Predicate來創(chuàng)建更復(fù)
雜的謂詞。比如,你可以使用negate方法來返回一個Predicate的非,比如蘋果不是紅的:PredicatenotRedApple = redApple.negate(); 你可能想要把兩個Lambda用and方法組合起來,比如一個蘋果既是紅色又比較重:
PredicateredAndHeavyApple = redApple.and(a -> a.getWeight() > 150); 你可以進(jìn)一步組合謂詞,表達(dá)要么是重(150克以上)的紅蘋果,要么是綠蘋果:
PredicateredAndHeavyAppleOrGreen = redApple.and(a -> a.getWeight() > 150) .or(a -> "green".equals(a.getColor())); 這一點為什么很好呢?從簡單Lambda表達(dá)式出發(fā),你可以構(gòu)建更復(fù)雜的表達(dá)式,但讀起來仍然和問題的陳述差不多!請注意,and和or方法是按照在表達(dá)式鏈中的位置,從左向右確定優(yōu)先級的。因此,a.or(b).and(c)可以看作(a || b) && c。
你還可以把Function接口所代表的Lambda表達(dá)式復(fù)合起來。Function接口為此配了andThen和compose兩個默認(rèn)方法,它們都會返回Function的一個實例。
andThen方法會返回一個函數(shù),它先對輸入應(yīng)用一個給定函數(shù),再對輸出應(yīng)用另一個函數(shù);用compose方法,先把給定的函數(shù)用作compose的參>數(shù)里面給的那個函數(shù),然后再把函數(shù)本身用于結(jié)果。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/77537.html
摘要:通常,這種模式是通過定義一個代表處理對象的抽象類來實現(xiàn)的,在抽象類中會定義一個字段來記錄后續(xù)對象。工廠模式使用表達(dá)式第章中,我們已經(jīng)知道可以像引用方法一樣引用構(gòu)造函數(shù)。 一、為改善可讀性和靈活性重構(gòu)代碼 1.改善代碼的可讀性 Java 8的新特性也可以幫助提升代碼的可讀性: 使用Java 8,你可以減少冗長的代碼,讓代碼更易于理解 通過方法引用和Stream API,你的代碼會變得更...
摘要:但是,最好使用差異化的類型定義,函數(shù)簽名如下其實二者說的是同一件事。后者的返回值和初始函數(shù)的返回值相同,即。破壞式更新和函數(shù)式更新的比較三的延遲計算的設(shè)計者們在將引入時采取了比較特殊的方式。四匹配模式語言中暫時并未提供這一特性,略。 一、無處不在的函數(shù) 一等函數(shù):能夠像普通變量一樣使用的函數(shù)稱為一等函數(shù)(first-class function)通過::操作符,你可以創(chuàng)建一個方法引用,...
摘要:本文是函數(shù)式編程第二章的讀書筆記。的語法簡化了使用匿名內(nèi)部類時的模板代碼,讓程序員專注于編寫想要執(zhí)行的行為,也讓代碼更加簡潔易讀。中最重要的函數(shù)接口類型推斷為新成員表達(dá)式提供了類型推斷的支持,在不需要聲明參數(shù)類型的表達(dá)式中表現(xiàn)的有為明顯。 本文是「Java 8 函數(shù)式編程」第二章的讀書筆記。 Lambda引入的變化 Lambda表達(dá)式,是一種緊湊的、傳遞行為的方式,從編程思想上來講,...
摘要:依舊使用剛剛對蘋果排序的代碼。現(xiàn)在,要做的是篩選出所有的綠蘋果,也許你會這一個這樣的方法在之前,基本上都是這樣寫的,看起來也沒什么毛病。但是,現(xiàn)在又要篩選一下重量超過克的蘋果。 《Java8實戰(zhàn)》-讀書筆記第一章(01) 最近一直想寫點什么東西,卻不知該怎么寫,所以就寫寫關(guān)于看《Java8實戰(zhàn)》的筆記吧。 第一章內(nèi)容較多,因此打算分幾篇文章來寫。 為什么要關(guān)心Java8 自1996年J...
摘要:內(nèi)部迭代與使用迭代器顯式迭代的集合不同,流的迭代操作是在背后進(jìn)行的。流只能遍歷一次請注意,和迭代器類似,流只能遍歷一次。 流(Stream) 流是什么 流是Java API的新成員,它允許你以聲明性方式處理數(shù)據(jù)集合(通過查詢語句來表達(dá),而不是臨時編寫一個實現(xiàn))。就現(xiàn)在來說,你可以把它們看成遍歷數(shù)據(jù)集的高級迭代器。此外,流還可以透明地并行處理,你無需寫任何多線程代碼了!我會在后面的筆記中...
摘要:實戰(zhàn)讀書筆記第一章從方法傳遞到接著上次的,繼續(xù)來了解一下,如果繼續(xù)簡化代碼。去掉并且生成的數(shù)字是萬,所消耗的時間循序流并行流至于為什么有時候并行流效率比循序流還低,這個以后的文章會解釋。 《Java8實戰(zhàn)》-讀書筆記第一章(02) 從方法傳遞到Lambda 接著上次的Predicate,繼續(xù)來了解一下,如果繼續(xù)簡化代碼。 把方法作為值來傳遞雖然很有用,但是要是有很多類似與isHeavy...
閱讀 3810·2021-11-12 10:34
閱讀 2824·2021-09-22 15:14
閱讀 793·2019-08-30 15:53
閱讀 3207·2019-08-30 12:53
閱讀 1296·2019-08-29 18:32
閱讀 2775·2019-08-29 16:41
閱讀 1071·2019-08-26 13:40
閱讀 1816·2019-08-23 18:07