java8 list 行转列_Java14 都来了,你还不会用 Java8吗?
Java 8 于2014年3月18日發(fā)布,并且成為主流的 Java,如今,雖然 Java 14 都已經(jīng)發(fā)布了,但是 開發(fā)者和公司選擇的版本依舊是經(jīng)久不衰的 Java 8 版本,如果你還不了解這些新特性,是時候?qū)W習(xí)一下了。
Java 8 更新的一些重要功能一覽
- Iterable 接口中的 forEach() 方法
- 接口中的默認方法和靜態(tài)方法
- 功能接口和 Lambda 表達式
- 用于集合上批量數(shù)據(jù)操作的 Java Stream API
- Java 時間 API
- 集合 API 的改進
- 并發(fā) API 改進
- Java IO改進
- 其他核心 API 改進
下面來簡要了解一下這些Java 8功能。我將提供一些代碼片段以更好地理解,因此,如果要在Java 8中運行程序,則必須按照以下步驟設(shè)置Java 8環(huán)境。
下載并安裝JDK8。像其他Java版本一樣,安裝也很簡單,運行下面的示例,必須要安裝 JDK 環(huán)境。
下載最新的 IDEA 開發(fā)環(huán)境,這里我不推薦使用 Eclipse ,但是如果你有使用 Eclipse 習(xí)慣,那我在這里推薦你可以嘗試 IDEA,因為它真的太棒啦~
Iterable 接口中的 forEach()方法
在 Java 8 以前,每當需要遍歷 Collection 時,就需要創(chuàng)建一個 Iterator 來進行迭代 Collection 對象,然后針對 Collection 中 的每個元素將業(yè)務(wù)邏輯循環(huán)在一起。如果迭代器使用不正確,可能會拋出 ConcurrentModificationException。
Java 8 在接口中引入了forEach方法,java.lang.Iterable因此在編寫代碼時,我們僅關(guān)注業(yè)務(wù)邏輯。forEach方法將java.util.function.Consumer對象作為參數(shù),因此有助于將我們的業(yè)務(wù)邏輯放在一個可以重用的單獨位置。讓我們通過簡單的示例查看forEach用法。
package?com.journaldev.java8.foreach;import?java.util.ArrayList;import?java.util.Iterator;import?java.util.List;import?java.util.function.Consumer;import?java.lang.Integer;public?class?Java8ForEachExample?{????public?static?void?main(String[]?args)?{????????//creating?sample?Collection????????List?myList?=?new?ArrayList();????????for(int?i=0;?i<10;?i++)?myList.add(i);????????//traversing?using?Iterator????????Iterator?it?=?myList.iterator();????????while(it.hasNext()){????????????Integer?i?=?it.next();????????????System.out.println("Iterator?Value::"+i);????????}????????//traversing?through?forEach?method?of?Iterable?with?anonymous?class????????myList.forEach(new?Consumer()?{????????????public?void?accept(Integer?t)?{????????????????System.out.println("forEach?anonymous?class?Value::"+t);????????????}????????});????????//traversing?with?Consumer?interface?implementation????????MyConsumer?action?=?new?MyConsumer();????????myList.forEach(action);????}}//Consumer?implementation?that?can?be?reusedclass?MyConsumer?implements?Consumer{????public?void?accept(Integer?t)?{????????System.out.println("Consumer?impl?Value::"+t);????}}代碼的行數(shù)可能會增加,但是forEach方法有助于將迭代邏輯和業(yè)務(wù)邏輯放在不同的位置,從而使關(guān)注點和代碼更清晰地分離。
接口中的默認方法和靜態(tài)方法
如果仔細閱讀forEach方法的詳細信息,會注意到它是在Iterable接口中定義的,但我們知道接口不能具有方法主體。從Java 8開始,接口已增強為具有實現(xiàn)的方法。我們可以使用default和static關(guān)鍵字來創(chuàng)建帶有方法實現(xiàn)的接口。Iterable接口中的forEach方法實現(xiàn)為:
default?void?forEach(Consumer?super?T>?action)?{????Objects.requireNonNull(action);????for?(T?t?:?this)?{????????action.accept(t);????}}我們知道Java不會在Class中提供多重繼承,因為它會導(dǎo)致Diamond問題。由于接口現(xiàn)在類似于抽象類,因此現(xiàn)在如何使用接口處理它。解決方案是在這種情況下編譯器將引發(fā)異常,我們將不得不在實現(xiàn)接口的類中提供實現(xiàn)邏輯。
package?com.journaldev.java8.defaultmethod;@FunctionalInterfacepublic?interface?Interface1?{????void?method1(String?str);????default?void?log(String?str){????????System.out.println("I1?logging::"+str);????}????static?void?print(String?str){????????System.out.println("Printing?"+str);????}????//trying?to?override?Object?method?gives?compile-time?error?as????//"A?default?method?cannot?override?a?method?from?java.lang.Object"//????default?String?toString(){//????????return?"i1";//????}}package?com.journaldev.java8.defaultmethod;@FunctionalInterfacepublic?interface?Interface2?{????void?method2();????default?void?log(String?str){????????System.out.println("I2?logging::"+str);????}}注意,兩個接口都有一個帶有實現(xiàn)邏輯的通用方法log()。
package?com.journaldev.java8.defaultmethod;public?class?MyClass?implements?Interface1,?Interface2?{????@Override????public?void?method2()?{????}????@Override????public?void?method1(String?str)?{????}????//MyClass?won't?compile?without?having?it's?own?log()?implementation????@Override????public?void?log(String?str){????????System.out.println("MyClass?logging::"+str);????????Interface1.print("abc");????}}如你所見, Interface1 具有在 MyClass.log() 方法實現(xiàn)中使用的靜態(tài)方法實現(xiàn)。Java 8 在 Collection API 中大量使用默認和靜態(tài)方法,并且添加了默認方法,以便使 JDK 8 之前的代碼保持向后兼容。
如果層次結(jié)構(gòu)中的任何類都具有具有相同的方法,則默認方法將變得無關(guān)緊要。由于任何實現(xiàn)接口的類都已經(jīng)具有 Object 作為超類,因此如果接口中具有 equals(),hashCode() 默認方法,它將變得無關(guān)緊要。這就是為什么為了更清楚起見,不允許接口具有Object默認方法。
有關(guān)Java 8接口特性的完整詳細信息,請閱讀 Java 8接口更改。
功能接口和Lambda表達式
如果你注意到上述接口代碼,則會注意到 @FunctionalInterface 注解。該功能接口是Java 8 中引入的新概念。具有一種抽象方法的接口就變成了功能接口。我們不需要使用 @FunctionalInterface 注解將接口標記為Functional Interface。@FunctionalInterface 注解是一種避免在功能接口中意外添加抽象方法的工具。您可以將其視為 @Override 批注,并且是使用它的最佳實踐。java.lang.Runnable 使用單個抽象方法 run() 是功能接口的一個很好的例子。
功能接口的主要優(yōu)點之一是可以使用 lambda 表達式實例化它們。在 Java 8 之前,可以用匿名類實例化一個接口,但是代碼看起來很龐大。
Runnable?r?=?new?Runnable(){????@Override????public?void?run()?{????????????System.out.println("My?Runnable");????}};由于功能接口只有一種方法,因此 lambda 表達式可以輕松提供該方法的實現(xiàn)。只需要提供方法參數(shù)和業(yè)務(wù)邏輯。例如,可以使用 lambda 表達式編寫上面的實現(xiàn):
Runnable?r1?=?()?->?{????????????System.out.println("My?Runnable");????????};如果方法實現(xiàn)中只有一條語句,那么我們也不需要花括號。例如,上面的Interface1匿名類可以使用lambda實例化,如下所示:
Interface1?i1?=?(s)?->?System.out.println(s);i1.method1("abc");因此,lambda 表達式是輕松創(chuàng)建功能接口的匿名類的一種方法。使用 lambda 表達式對于代碼運行沒有任何的影響,因此要謹慎謹慎使用它,因為我們并不介意編寫一些額外的代碼行。
新包裝 java.util.function 添加了帶有功能接口束的,以提供 lambda 表達式和方法引用的目標類型。Lambda 表達式是一個非常復(fù)雜的話題,后續(xù)我會編寫一篇文章專門針對 lambda 表達式。
您可以在 Java 8 Lambda Expressions Tutorial 中閱讀完整的教程。
用于集合上批量數(shù)據(jù)操作的Java Stream API
java.util.stream 是Java 8中添加的一個新內(nèi)容,以對該集合執(zhí)行類似過濾/映射/遍歷的操作。Stream API 將允許順序執(zhí)行和并行執(zhí)行。這對我來說是非常好用的一個功能,因為我經(jīng)常處理 Collections,而且通常使用很多的數(shù)據(jù)進行過濾數(shù)據(jù),遍歷數(shù)據(jù),stream 就完美的解決了這個問題。
Collection 接口已使用 stream() 和 parallelStream() 默認方法進行了擴展,以獲取用于順序執(zhí)行和并行執(zhí)行的 Stream ,用一個簡單的例子看看它們的用法。
package?com.journaldev.java8.stream;import?java.util.ArrayList;import?java.util.List;import?java.util.stream.Stream;public?class?StreamExample?{????public?static?void?main(String[]?args)?{????????List?myList?=?new?ArrayList<>();????????for(int?i=0;?i<100;?i++)?myList.add(i);????????//sequential?stream????????Stream?sequentialStream?=?myList.stream();????????//parallel?stream????????Stream?parallelStream?=?myList.parallelStream();????????//using?lambda?with?Stream?API,?filter?example????????Stream?highNums?=?parallelStream.filter(p?->?p?>?90);????????//using?lambda?in?forEach????????highNums.forEach(p?->?System.out.println("High?Nums?parallel="+p));????????Stream?highNumsSeq?=?sequentialStream.filter(p?->?p?>?90);????????highNumsSeq.forEach(p?->?System.out.println("High?Nums?sequential="+p));????}}如果你運行示例代碼,將獲得如下輸出:
High?Nums?parallel=91High?Nums?parallel=96High?Nums?parallel=93High?Nums?parallel=98High?Nums?parallel=94High?Nums?parallel=95High?Nums?parallel=97High?Nums?parallel=92High?Nums?parallel=99High?Nums?sequential=91High?Nums?sequential=92High?Nums?sequential=93High?Nums?sequential=94High?Nums?sequential=95High?Nums?sequential=96High?Nums?sequential=97High?Nums?sequential=98High?Nums?sequential=99請注意,并行處理的時候。值不按順序排列,因此在處理龐大的集合時,并行處理將非常有幫助。
這篇文章無法涵蓋有關(guān)Stream API的所有內(nèi)容,您可以在 Java 8 Stream API Example Tutorial 中閱讀有關(guān)Stream API的所有內(nèi)容。
Java 8 時間API
在之前的 Java 中使用日期,時間和時區(qū)一直很困難。Java 中沒有用于日期和時間的標準方法或 API。Java 8 有一個不錯的附加功能是 java.time 軟件包,它簡化了 Java 中使用時間的過程。
僅查看 Java Time API 軟件包,就可以感覺到它非常易于使用。它具有一些子包 java.time.format,這些子包提供用于打印和解析日期和時間的類,還有java.time.zone 提供對時區(qū)及其規(guī)則的支持。
新的 Time API 在整月的幾個月和一周中的幾天中都使用了枚舉而不是整數(shù)常量。常用的類之一是 DateTimeFormatter 將 DateTime 對象轉(zhuǎn)換為字符串。
有關(guān)完整的教程,請轉(zhuǎn)到 Java日期時間API示例教程。
集合API的改進
在上面的介紹已經(jīng)看到了 forEach() 方法和用于集合的 Stream API。
Collection API 中添加的一些新方法是:
IteratorforEachRemaining(Consumer action) 在所有元素都已處理完畢或該動作引發(fā)異常之前,對其余每個元素執(zhí)行給定操作的默認方法。
CollectionremoveIf(Predicate filter) 刪除此集合中所有滿足給定謂詞的元素的默認方法。
Collection spliterator() 該方法返回Spliterator實例,該實例可用于順序或并行遍歷元素。地圖replaceAll(),compute(),merge()方法。
另外還有一些具有 hash 沖突 的HashMap 類的性能改進
并發(fā)API改進
一些重要的并發(fā)API增強功能包括:
ConcurrentHashMap compute(),forEach(),forEachEntry(),forEachKey(),forEachValue(),merge(),reduce()和search()方法。CompletableFuture 可以明確完成(設(shè)置其值和狀態(tài))。Executors newWorkStealingPool() 使用所有可用處理器作為目標并行度級別創(chuàng)建竊取線程池的方法。
Java IO改進
我知道的一些IO改進:
Files.list(Path dir) 返回一個延遲加載的 Stream,其元素是目錄中的文件夾和文件列表。
Files.lines(Path path) 返回一個讀取指定文件所有行的文件流。
Files.find() 返回一個根據(jù)指定目錄搜索指定文件的文件列表流。
BufferedReader.lines() 返回一個Stream,其元素是從此 BufferedReader 中讀取的行。
其他核心API改進
一些雜項API改進在某些特殊情況可能會派上用場:
- ThreadLocal 靜態(tài)方法可以使用 withInitial 方法創(chuàng)建實例。
- 比較器接口已擴展了許多默認和靜態(tài)方法,用于自然排序,反向排序等。
- Integer,Long 和 Double 包裝器類中增加了 min(),max() 和 sum() 方法。
- Boolean 類中的 logicalAnd() ,logicalOr() 和 logicalXor() 方法。
- ZipFile.stream() 方法獲取 ZIP 文件條目上的有序Stream,并以壓縮時的順序出現(xiàn)在 Stream 中。
- Math 類中增加了幾種實用方法。
- jjs 添加命令以調(diào)用 Nashorn Engine。
- jdeps 添加命令以分析類文件
- JDBC-ODBC 橋已被刪除。
- PermGen 內(nèi)存空間已被刪除
碼字不易,如果能幫到你,請點點關(guān)注~
總結(jié)
以上是生活随笔為你收集整理的java8 list 行转列_Java14 都来了,你还不会用 Java8吗?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 早报:荣耀Magic5系列新机入网 美国
- 下一篇: 全球第一次!DDR5内存加上一颗特殊芯片