摘要:一個(gè)抽象類可以通過實(shí)例變量字段保存一個(gè)通用狀態(tài),而接口是不能有實(shí)例變量的。分組和分區(qū)分組多級(jí)分組分區(qū)是分組的特殊情況由一個(gè)謂詞返回一個(gè)布爾值的函數(shù)作為分類函數(shù),它稱分區(qū)函數(shù)。
一、基本概念
兩個(gè)新特性:
1、函數(shù)式編程簡化代碼復(fù)雜度(引入了Lambda表達(dá)式) 2、更高效的利用多核CPU1、基本概念:
1、Lambda基本語法 (parameters) -> expression 對(duì)應(yīng):參數(shù)->表達(dá)式 或(請(qǐng)注意語句的花括號(hào)) (parameters) -> { statements; } 對(duì)應(yīng):參數(shù)->語句
根據(jù)上述語法規(guī)則,以下哪個(gè)不是有效的Lambda表達(dá)式?
(1) () -> {} (2) () -> "Raoul" (3) () -> {return "Mario";} (4) (Integer i) -> return "Alan" + i; (5) (String s) -> {"IronMan";}
答案:只有4和5是無效的Lambda。
(1) 這個(gè)Lambda沒有參數(shù),并返回void。它類似于主體為空的方法:public void run() {}。
(2) 這個(gè)Lambda沒有參數(shù),并返回String作為表達(dá)式。
(3) 這個(gè)Lambda沒有參數(shù),并返回String(利用顯式返回語句)。
(4) return是一個(gè)控制流語句。要使此 Lambda有效,需要使花括號(hào),如下所示:
(Integer i) -> {return "Alan" + i;}。
(5)"Iron Man"是一個(gè)表達(dá)式,不是一個(gè)語句。要使此 Lambda有效,你可以去除花括號(hào)
和分號(hào),如下所示:(String s) -> "Iron Man"。或者如果你喜歡,可以使用顯式返回語
句,如下所示:(String s)->{return "IronMan";}。
函數(shù)式接口就是只定義一個(gè)抽象方法的接口。 下列哪些式函數(shù)式接口: (1)public interface Adder{ int add(int a, int b); } (2)public interface SmartAdder extends Adder{ int add(double a, double b); } (3)public interface Nothing{ } 只有(1)是函數(shù)式接口,按照定義其他都不是。3、Java 8中的抽象類和抽象接口
(1)一個(gè)類只能繼承一個(gè)抽象類,但是一個(gè)類可以實(shí)現(xiàn)多個(gè)接口。
(2)一個(gè)抽象類可以通過實(shí)例變量(字段)保存一個(gè)通用狀態(tài),而接口是不能有實(shí)例變量的。
(1) 類中的方法優(yōu)先級(jí)最高。類或父類中聲明的方法的優(yōu)先級(jí)高于任何聲明為默認(rèn)方法的優(yōu)先級(jí)。 (2) 如果無法依據(jù)第一條進(jìn)行判斷,那么子接口的優(yōu)先級(jí)更高:函數(shù)簽名相同時(shí), 優(yōu)先選擇擁有最具體實(shí)現(xiàn)的默認(rèn)方法的接口,即如果B 繼承了A ,那么B 就比A 更加具體。 (3) 最后,如果還是無法判斷,繼承了多個(gè)接口的類必須通過顯式覆蓋和調(diào)用期望的方法, 顯式地選擇使用哪一個(gè)默認(rèn)方法的實(shí)現(xiàn)。5、教你一步步完成普通方法到Lambda方法的改造
目標(biāo):對(duì)于一個(gè)`Apple`列表(`inventory`)按照重量進(jìn)行排序 最終實(shí)現(xiàn):`inventory.sort(comparing(Apple::getWeight))`
實(shí)現(xiàn)分析:
Java 8的 API已經(jīng)為你提供了一個(gè)List可用的sort方法,你不用自己去實(shí)現(xiàn)它。
那么最困難的部分已經(jīng)搞定了!但是,如何把排序策略傳遞給sort方法呢?你看,sort方法的簽名是這樣的:
void sort(Comparator super E> c)
它需要一個(gè)Comparator對(duì)象來比較兩個(gè)Apple!這就是在 Java中傳遞策略的方式:它們必須包裹在一個(gè)對(duì)象里。
我們說sort的行為被參數(shù)化了:傳遞給它的排序策略不同,其行為也會(huì)不同。
public class AppleComparator implements Comparator{ public int compare(Apple a1, Apple a2){ return a1.getWeight().compareTo(a2.getWeight()); } } inventory.sort(new AppleComparator());
你在前面看到了,你可以使用匿名類來改進(jìn)解決方案, 而不是實(shí)現(xiàn)一個(gè)`Comparator`卻只實(shí)例化一次:
inventory.sort(new Comparator() { public int compare(Apple a1, Apple a2){ return a1.getWeight().compareTo(a2.getWeight()); } });
使用Lambda 表達(dá)式 你的解決方案仍然挺啰嗦的。Java 8引入了Lambda表達(dá)式, 它提供了一種輕量級(jí)語法來實(shí)現(xiàn)相同的目標(biāo):傳遞代碼。 你看到了,在需要函數(shù)式接口的地方可以使用Lambda表達(dá)式。 我們回顧一下:函數(shù)式接口就是僅僅定義一個(gè)抽象方法的接口。 抽象方法的簽名(稱為函數(shù)描述符)描述了Lambda表達(dá)式的簽名。 在這個(gè)例子里,Comparator代表了函數(shù)描述符(T, T) -> int。 因?yàn)槟阌玫氖翘O果,所以它具體代表的就是(Apple, Apple) -> int。 改進(jìn)后的新解決方案看上去就是這樣的了: inventory.sort((Apple a1, Apple a2)->a1.getWeight().compareTo(a2.getWeight())); 我們前面解釋過了,Java 編譯器可以根據(jù)Lambda 出現(xiàn)的上下文來推斷 Lambda 表達(dá)式參數(shù)的類型 。那么你的解決方案就可以重寫成這樣: inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight())); 你的代碼還能變得更易讀一點(diǎn)嗎?Comparator 具有一個(gè)叫作comparing 的靜態(tài)輔助方法,它可以接受一個(gè)Functio 來提取Comparable 鍵值,并 生成一個(gè)Comparator 對(duì)象。 它可以像下面這樣用(注意你現(xiàn)在傳遞的Lambda 只有一個(gè)參數(shù):Lambda 說明了如何從蘋果中提取需要比較的鍵值): Comparatorc = Comparator.comparing((Apple a) -> a.getWeight()); 現(xiàn)在你可以把代碼再改得緊湊一點(diǎn)了: import static java.util.Comparator.comparing; inventory.sort(comparing((a) -> a.getWeight()));
使用方法引用 前面解釋過,方法引用就是替代那些轉(zhuǎn)發(fā)參數(shù)的Lambda表達(dá)式的語法糖。你可以用方法引用讓你的代碼更簡潔 假設(shè)你靜態(tài)導(dǎo)入了 import java.util.Comparator.comparing; inventory.sort(comparing(Apple::getWeight));二、流簡介
流是`Java API`的新成員,它允許你以聲明性方式處理數(shù)據(jù)集合(通過查詢語句來表達(dá),而不是臨時(shí)編寫一個(gè)實(shí)現(xiàn))。就現(xiàn)在來說,你可以把它們看成遍歷數(shù)據(jù)集的高級(jí)迭代器。 流可以并行的處理集合數(shù)據(jù),無需編寫復(fù)雜的多線程代碼。
public class Dish { private final String name; private final boolean vegetarian; private final int calories; private final Type type; public Dish(String name, boolean vegetarian, int calories, Type type) { this.name = name; this.vegetarian = vegetarian; this.calories = calories; this.type = type; } public String getName() { return name; } public boolean isVegetarian() { return vegetarian; } public int getCalories() { return calories; } public Type getType() { return type; } public enum Type { MEAT, FISH, OTHER } }
目標(biāo):篩選出盤子中熱量高于400的食物的名稱,并按按照熱量高低排序
方法一:用普通集合方式處理
ListlowCaloricDishes = new ArrayList<>(); //1、篩選 for(Dish d: menu){ if(d.getCalories() < 400){ lowCaloricDishes.add(d); } } //2、排序 Collections.sort(lowCaloricDishes, new Comparator () { public int compare(Dish d1, Dish d2){ return Integer.compare(d1.getCalories(), d2.getCalories()); } }); //3、統(tǒng)計(jì) List lowCaloricDishesName = new ArrayList<>(); for(Dish d: lowCaloricDishes){ lowCaloricDishesName.add(d.getName()); }
方法二:用流處理
ListlowCaloricDishesName = menu.stream() .filter(d->d.getCalories()<400)// 篩選 .sorted(comparing(Dish::getCalories))//排序 .map(d->d.getName()) .collect(Collectors.toList());//統(tǒng)計(jì)
流的特點(diǎn): ? 元素序列——就像集合一樣,流也提供了一個(gè)接口,可以訪問特定元素類型的一組有序值。因?yàn)榧鲜菙?shù)據(jù)結(jié)構(gòu),所以它的主要目的是以特定的時(shí)間/空間復(fù)雜度存儲(chǔ)和訪問元 素(如`ArrayList` 與 `LinkedList`)。但流的目的在于表達(dá)計(jì)算,比如 `filter`、`sorted`和`map`。集合講的是數(shù)據(jù),流講的是計(jì)算。 ? 源——流會(huì)使用一個(gè)提供數(shù)據(jù)的源,如集合、數(shù)組或輸入/輸出資源。 請(qǐng)注意,從有序集合生成流時(shí)會(huì)保留原有的順序。由列表生成的流,其元素順序與列表一致。 ? 數(shù)據(jù)處理操作——流的數(shù)據(jù)處理功能支持類似于數(shù)據(jù)庫的操作,如`filter`、`map`、`reduce`、`find`、`match`、`sort`等。流操作可以順序執(zhí)行,也可并行執(zhí)行。 ? 流水線——很多流操作本身會(huì)返回一個(gè)流,這樣多個(gè)操作就可以鏈接起來,形成一個(gè)大的流水線。流水線的操作可以看作對(duì)數(shù)據(jù)源進(jìn)行數(shù)據(jù)庫式查詢。 ? 內(nèi)部迭代——與使用迭代器顯式迭代的集合不同,流的迭代操作是在背后進(jìn)行的。 流與集合的區(qū)別: 1、集合是一個(gè)內(nèi)存中的數(shù)據(jù)結(jié)構(gòu),它包含數(shù)據(jù)結(jié)構(gòu)中目前所有的值—— 集合中的每個(gè)元素都得先算出來才能添加到集合中。 2、流則是在概念上固定的數(shù)據(jù)結(jié)構(gòu)(你不能添加或刪除元素),其元素則是按需計(jì)算的。 流的操作: 1、中間操作:中間操作會(huì)返回另一個(gè)流,比如`filter、map、sort、distinct`等操作 2、終端操作: 終端操作會(huì)從流的流水線生成結(jié)果,比如`forEach、count、collect`三、使用流
常用流的API介紹
1、篩選流
Listnumbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); numbers.stream() .filter(i -> i % 2 == 0) .distinct() .forEach(System.out::println);
2、截?cái)嗔?/p>
Listdishes = menu.stream() .filter(d -> d.getCalories() > 300) .limit(3) .collect(toList());
3、跳過元素
Listdishes = menu.stream() .filter(d -> d.getCalories() > 300) .skip(2) .collect(toList());
4、映射 對(duì)流中每一個(gè)元素應(yīng)用函數(shù)
ListdishNames = menu.stream() .map(Dish::getName) .collect(toList()); List dishNameLengths = menu.stream() .map(Dish::getName) .map(String::length) .collect(toList());
5、流的扁平化
例如, 給定單詞列表["Hello","World"] ,你想要返回列表["H","e","l", "o","W","r","d"]
方式一:這個(gè)并不能返回正確的數(shù)據(jù),解釋看圖5-5
words.stream() .map(word -> word.split("")) .distinct() .collect(toList());
方式二:使用`flatMap` 方法,把一個(gè)流中的每個(gè)值都換成另一個(gè)流,然后把所有的流連接起來成為一個(gè)流。解釋看圖5-6
ListuniqueCharacters = words.stream() .map(w -> w.split("")) .flatMap(Arrays::stream) .distinct() .collect(Collectors.toList());
6、查找和匹配
Stream API通過allMatch 、anyMatch 、noneMatch 、findFirst 和findAny 方法提供了查找和匹配的工具方法。
1、anyMatch方法可以回答“流中是否有一個(gè)元素能匹配給定的謂詞”。
if(menu.stream().anyMatch(Dish::isVegetarian)){ System.out.println("The menu is (somewhat) vegetarian friendly!!"); } anyMatch方法返回一個(gè)boolean,因此是一個(gè)終端操作。
2、allMatch方法的工作原理和anyMatch類似,但它會(huì)看看流中的元素是否都能匹配給定的謂詞。
boolean isHealthy = menu.stream().allMatch(d -> d.getCalories() < 1000);
3、noneMatch沒有任何元素與給定的謂詞匹配。
boolean isHealthy = menu.stream().noneMatch(d -> d.getCalories() < 1000);
4、findAny方法將返回當(dāng)前流中的任意元素。
Optionaldish =menu.stream().filter(Dish::isVegetarian).findAny(); Optional簡介 Optional 類(java.util.Optional)是一個(gè)容器類, 代表一個(gè)值存在或不存在。在上面的代碼中,findAny可能 什么元素都沒找到。Java 8的庫設(shè)計(jì)人員引入了Optional , 這樣就不用返回眾所周知容易出問題的null了。
5、findFirst查找第一個(gè)元素
ListsomeNumbers = Arrays.asList(1, 2, 3, 4, 5); Optional firstSquareDivisibleByThree =someNumbers.stream() .map(x -> x * x) .filter(x -> x % 3 == 0) .findFirst(); // 9
6、規(guī)約
解決了如何把一個(gè)流中的元素組合起來,常用函數(shù)reduce 數(shù)據(jù)求和實(shí)現(xiàn) 方式一: int sum = 0; for (int x : numbers) { sum += x; } 方式二: int sum = numbers.stream().reduce(0, (a, b) -> a + b); 解釋: reduce接受兩個(gè)參數(shù): ? 一個(gè)初始值,這里是0; ? 一個(gè)BinaryOperator來將兩個(gè)元素結(jié)合起來產(chǎn)生一個(gè)新的值,這里我們用的是lambda (a, b) -> a + b 。 求最大值和最小值 int max = numbers.stream().reduce(0, Integer::max);
歸約方法的優(yōu)勢(shì)與并行化
相比于前面寫的逐步迭代求和,使用reduce的好處在于,這里的迭代被內(nèi)部迭代抽象掉了, 這讓內(nèi)部實(shí)現(xiàn)得以選擇并行執(zhí)行reduce操作。而迭代式求和例子要更新共享變量sum, 這不是那么容易并行化的。 如果你加入了同步,很可能會(huì)發(fā)現(xiàn)線程競(jìng)爭(zhēng)抵消了并行本應(yīng)帶來的性能提升!這種計(jì)算的并 行化需要另一種辦法:將輸入分塊,分塊求和,最后再合并起來。但這樣的話代碼看起來就 完全不一樣了。 使用流來對(duì)所有的元素并行求和時(shí),你的代碼幾乎不用修改:stream()換成了`parallelStream()。 int sum = numbers.parallelStream().reduce(0, Integer::sum);
7、構(gòu)建流
從數(shù)值、數(shù)組、序列、文件以及函數(shù)來構(gòu)建流
7.1、數(shù)值構(gòu)建流
Streamstream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action"); stream.map(String::toUpperCase).forEach(System.out::println);
7.2、數(shù)組構(gòu)建流
int[] numbers = {2, 3, 5, 7, 11, 13}; int sum = Arrays.stream(numbers).sum();
7.3、函數(shù)構(gòu)建流 Stream API提供了兩個(gè)靜態(tài)方法來從函數(shù)生成流:
Stream.iterate和 Stream.generate。 Stream.iterate迭代構(gòu)建流: Stream.iterate(0, n -> n + 2).limit(10).forEach(System.out::println);
解釋:
iterate方法接受一個(gè)初始值(在這里是0), 還有一個(gè)依次應(yīng)用在每個(gè)產(chǎn)生的新值上的Lambda(UnaryOperator四、流的收集器類型)。 這里,我們使用Lambda n -> n + 2,返回的是前一個(gè)元素加上2。 Stream.generate生成流: Stream.generate(Math::random).limit(5).forEach(System.out::println); IntStream 的generate 方法會(huì)接受一個(gè)IntSupplier,可以這樣來生成一個(gè)全是1 的無限流。 IntStream ones = IntStream.generate(() -> 1);
收集器非常有用,因?yàn)橛盟梢院啙嵍`活地定義collect 用來生成結(jié)果集合的標(biāo)準(zhǔn),一個(gè)普通的收集器 收集器的主要功能: ? 將流元素歸約和匯總為一個(gè)值 ? 元素分組 ? 元素分區(qū) 首先導(dǎo)入類:import static java.util.stream.Collectors.*;
1、歸約和匯總
long howManyDishes = menu.stream().count(); int totalCalories = menu.stream().collect(summingInt(Dish::getCalories))
2、連接字符串
String shortMenu = menu.stream().map(Dish::getName).collect(joining()); String shortMenu = menu.stream().map(Dish::getName).collect(joining(", "));
3、廣義的歸約匯總
int totalCalories = menu.stream().collect(reducing(0, Dish::getCalories, (i, j) -> i + j)); 解釋它需要三個(gè)參數(shù)。 ? 第一個(gè)參數(shù)是歸約操作的起始值,也是流中沒有元素時(shí)的返回值,所以很顯然對(duì)于數(shù)值和而言0是一個(gè)合適的值。 ? 第二個(gè)參數(shù)就是你在6.2.2節(jié)中使用的函數(shù),將菜肴轉(zhuǎn)換成一個(gè)表示其所含熱量的int。 ? 第三個(gè)參數(shù)是一個(gè)BinaryOperator,將兩個(gè)項(xiàng)目累積成一個(gè)同類型的值。這里它就是對(duì)兩個(gè)int求和。
4、分組和分區(qū)groupingBy
4.1、分組 Map> dishesByType =menu.stream().collect(groupingBy(Dish::getType)); 4.2、多級(jí)分組 Map >> groupByTypeAndCaloriesMap=menu.stream() .collect( Collectors.groupingBy( Dish::getType, Collectors.groupingBy(dish -> { if(dish.getCalories()<=400){ return CaloricLevel.DIET; }else if(dish.getCalories()<=700){ return CaloricLevel.NORMAL; }else{ return CaloricLevel.FAT; } }) ));
5、分區(qū)是分組的特殊情況:由一個(gè)謂詞(返回一個(gè)布爾值的函數(shù))作為分類函數(shù),它稱分區(qū)函數(shù) 。
分區(qū)函數(shù)返回一個(gè)布爾值,這意味著得到的分組Map 的鍵類型是Boolean ,于是它最多可以分 為兩組——true 是一組,false 是一組。 Map五、代碼重構(gòu)> partitionedMenu =menu.stream().collect(partitioningBy(Dish::isVegetarian));
Lambda表達(dá)式對(duì)面向?qū)ο蟮脑O(shè)計(jì)模式 說明:需要執(zhí)行的動(dòng)作都很簡單,使用Lambda方法能很方便地消除僵化代碼。但是, 觀察者的邏輯有可能十分復(fù)雜,它們可能還持有狀態(tài),或定義了多個(gè)方法,在這些情 形下,你還是應(yīng)該繼續(xù)使用類的方式。
1、使用Lambda 表達(dá)式重構(gòu)代碼
//具體處理文件接口 public interface BufferReaderProcessor{ String process(BufferedReader br) throws IOException; } //公共邏輯抽離:文件的打開、資源關(guān)閉 public static String processFile(String filePath,BufferReaderProcessor processor) throws IOException { try(BufferedReader br=new BufferedReader(new FileReader(filePath))){ return processor.process(br); } } //客戶端調(diào)用 String s1= processFile("data.txt",br->br.readLine()); String s2= processFile("data.txt",br->br.readLine()+br.readLine());
2、策略模式替換
//策略接口 public interface ValidationStrategy{ boolean execute(String s); } //策略執(zhí)行 public class Validator{ private ValidationStrategy strategy; public Validator(ValidationStrategy strategy){ this.strategy=strategy; } public boolean validator(String s){ return strategy.execute(s); } } //客戶端調(diào)用 Validator numberValidator=new Validator(s->s.matches("d+")); Validator lowerCaseValidator=new Validator(s->s.matches("[a-z]+")); numberValidator.validator("12345"); lowerCaseValidator.validator("abcdefg");六、異步編程
在Java?8中,?新增加了一個(gè)包含50個(gè)方法左右的類:?CompletableFuture, 提供了非常強(qiáng)大的Future的擴(kuò)展功能,可以幫助我們簡化異步編程的復(fù)雜性, 提供了函數(shù)式編程的能力,可以通過回調(diào)的方式處理計(jì)算結(jié)果,并且提供了轉(zhuǎn)換和 組合CompletableFuture的方法。
1、基本用法
CompletableFuture實(shí)現(xiàn)了Future接口,因此可以和使用Future一樣使用它。 1.1complete方法使用 CompletableFuturecompletableFuture=new CompletableFuture(); Thread thread=new Thread(()->{ System.out.println("task doing..."); try{ Thread.sleep(1000); }catch (Exception ex){ ex.printStackTrace(); } System.out.println("task done"); completableFuture.complete("finished");//設(shè)置任務(wù)完成標(biāo)識(shí),否則@1會(huì)一直傻等下去 }); thread.start(); String result=completableFuture.get();//@1 System.out.println("執(zhí)行結(jié)果:"+result);//返回finished 1.2 completeExceptionally 方法使用 CompletableFuture completableFuture=new CompletableFuture(); Thread thread=new Thread(()->{ try{ Thread.sleep(1000); throw new RuntimeException("拋異常了!"); }catch (Exception ex){ completableFuture.completeExceptionally(ex);//異常處理 } }); thread.start(); String result=completableFuture.get();
2、靜態(tài)方法
CompletableFuture 類自身提供了大量靜態(tài)方法,使用這些方法能更方便地進(jìn)行異步編程。
2.1、allOf和anyOf的使用
allOf要求所有任務(wù)都執(zhí)行完成,最后匯總執(zhí)行結(jié)果;anyOf只要執(zhí)行最快的線程返回,匯總結(jié)果。 1、task1 CompletableFuturecompletableFuture1=CompletableFuture.supplyAsync(()->{ try{ Thread.sleep(1500); }catch (Exception ex){ ex.printStackTrace(); } System.out.println("finished 1 "); return "completableFutue1"; }); 2、task2 CompletableFuture completableFuture2=CompletableFuture.supplyAsync(()->{ try{ Thread.sleep(1000); }catch (Exception ex){ ex.printStackTrace(); } System.out.println("finished 2 "); return "completableFuture2"; }); //兩個(gè)任務(wù)都要完成才能結(jié)束 CompletableFuture allResult=CompletableFuture.allOf(completableFuture1,completableFuture2); allResult.join(); //任一個(gè)任務(wù)結(jié)束就能返回 CompletableFuture
2.2 thenCompose
允許你對(duì)兩個(gè)異步操作進(jìn)行流水線, 第一個(gè)操作完成時(shí),將其結(jié)果作為參數(shù)傳遞給第二個(gè)操作。 CompletableFuturecompletedFuture1=CompletableFuture.supplyAsync(()->{ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return "Hello"; }); CompletableFuture completableFuture2=completedFuture1 .thenCompose(result->CompletableFuture.supplyAsync(()->result+" world")); String result=completableFuture2.get(); System.out.println("compose return:"+result);
3、ThenCombine
將兩個(gè)完 全不相干的 CompletableFuture 對(duì)象的結(jié)果整合起來, 而且你也不希望等到第一個(gè)任務(wù)完全結(jié)束才開始第二項(xiàng)任務(wù)。 CompletableFuturecompletableFuture1=CompletableFuture.supplyAsync(()->{ System.out.println("in completableFuture1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("finished completableFuture1"); return "Hello"; }); CompletableFuture completableFuture2=completableFuture1 .thenCombine(CompletableFuture.supplyAsync(()-> { System.out.println("in completableFuture2"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("finished completableFuture2"); return " World"; }),(result1,result2)->result1+result2); System.out.println(completableFuture2.get());
4、thenAccept
在每個(gè)CompletableFuture 上注冊(cè)一個(gè)操作, 該操作會(huì)在 CompletableFuture 完成執(zhí)行后調(diào)用它。 CompletableFuturecompletabledFuture1=CompletableFuture.supplyAsync(()->{ System.out.println("in completabledFuture1"); return "Hello"; }); completabledFuture1.thenAccept(result-> System.out.println("執(zhí)行結(jié)果:"+result));
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/70633.html
摘要:但是到了第二天,他突然告訴你其實(shí)我還想找出所有重量超過克的蘋果。現(xiàn)在,農(nóng)民要求需要篩選紅蘋果。那么,我們就可以根據(jù)條件創(chuàng)建一個(gè)類并且實(shí)現(xiàn)通過謂詞篩選紅蘋果并且是重蘋果酷,現(xiàn)在方法的行為已經(jīng)取決于通過對(duì)象來實(shí)現(xiàn)了。 通過行為參數(shù)化傳遞代碼 行為參數(shù)化 在《Java8實(shí)戰(zhàn)》第二章主要介紹的是通過行為參數(shù)化傳遞代碼,那么就來了解一下什么是行為參數(shù)化吧。 在軟件工程中,一個(gè)從所周知的問題就是,...
摘要:依舊使用剛剛對(duì)蘋果排序的代碼。現(xiàn)在,要做的是篩選出所有的綠蘋果,也許你會(huì)這一個(gè)這樣的方法在之前,基本上都是這樣寫的,看起來也沒什么毛病。但是,現(xiàn)在又要篩選一下重量超過克的蘋果。 《Java8實(shí)戰(zhàn)》-讀書筆記第一章(01) 最近一直想寫點(diǎn)什么東西,卻不知該怎么寫,所以就寫寫關(guān)于看《Java8實(shí)戰(zhàn)》的筆記吧。 第一章內(nèi)容較多,因此打算分幾篇文章來寫。 為什么要關(guān)心Java8 自1996年J...
摘要:語法中接口可以包含實(shí)現(xiàn)方法,需要使用修飾,此類方法稱為默認(rèn)方法。核心特性接口默認(rèn)方法就介紹到這里了,后續(xù)小樂會(huì)繼續(xù)講述核心特性。 JAVA8已經(jīng)發(fā)布很久,是自java5(2004年發(fā)布)之后Oracle發(fā)布的最重要的一個(gè)版本。其中包括語言、編譯器、庫、工具和JVM等諸多方面的新特性,對(duì)于國內(nèi)外互聯(lián)網(wǎng)公司來說,Java8是以后技術(shù)開發(fā)的趨勢(shì)。這里主要講解在開發(fā)中幾個(gè)核心的新特性。(主要從...
摘要:實(shí)戰(zhàn)讀書筆記第一章從方法傳遞到接著上次的,繼續(xù)來了解一下,如果繼續(xù)簡化代碼。去掉并且生成的數(shù)字是萬,所消耗的時(shí)間循序流并行流至于為什么有時(shí)候并行流效率比循序流還低,這個(gè)以后的文章會(huì)解釋。 《Java8實(shí)戰(zhàn)》-讀書筆記第一章(02) 從方法傳遞到Lambda 接著上次的Predicate,繼續(xù)來了解一下,如果繼續(xù)簡化代碼。 把方法作為值來傳遞雖然很有用,但是要是有很多類似與isHeavy...
摘要:大家好,我是樂字節(jié)的小樂,上一次我們說到了核心特性之函數(shù)式接口,接下來我們繼續(xù)了解又一核心特性方法引用。方法引用是一種更簡潔易懂的表達(dá)式。感謝光臨閱讀小樂的,敬請(qǐng)關(guān)注樂字節(jié)后續(xù)將繼續(xù)講述等前沿知識(shí)技術(shù)。 大家好,我是樂字節(jié)的小樂,上一次我們說到了Java8核心特性之函數(shù)式接口,接下來我們繼續(xù)了解Java8又一核心特性——方法引用。 showImg(https://segmentfaul...
閱讀 2663·2021-11-24 10:44
閱讀 1917·2021-11-22 13:53
閱讀 1937·2021-09-30 09:47
閱讀 3708·2021-09-22 16:00
閱讀 2438·2021-09-08 09:36
閱讀 2317·2019-08-30 15:53
閱讀 2793·2019-08-30 15:48
閱讀 986·2019-08-30 15:44