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