這篇文章主要介紹“JAVA 8新特性有哪些”,在日常操作中,相信很多人在JAVA 8新特性有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”JAVA 8新特性有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
為光山等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及光山網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站制作、光山網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
作為一個(gè)工作兩年多的 老 程序猿,雖然一開始就使用 jdk1.8 作為學(xué)習(xí)和使用的版本,隨著技術(shù)的迭代,現(xiàn)有的 JDK 版本從兩年前到現(xiàn)在,已經(jīng)飛速發(fā)展到了 JDK 15 。真的感覺有點(diǎn)學(xué)不動(dòng)了,更新速度太快了,不過相比于現(xiàn)有系統(tǒng)以及國內(nèi)趨勢。大多公司還是采用最基礎(chǔ)的 1.8 作為線上環(huán)境來使用。也是沒有任何問題的,不過我們真的 會(huì)使用 JAVA8 嗎?

本小結(jié)主要從 Lambda 表達(dá)式入手,由淺入深,按照實(shí)用性作為排行,逐步講解新特性帶給開發(fā)人員的快樂,如何更好的簡化代碼,優(yōu)化可讀性。這才是我們學(xué)習(xí)總結(jié)這一小節(jié)的一個(gè)目的。
從最基礎(chǔ)的循環(huán)開始,循環(huán)無非是我們剛學(xué)習(xí)的時(shí)候就需要接觸 for 這個(gè)最基本的循環(huán)結(jié)構(gòu),而且在后面的工作總都會(huì)大量使用的一個(gè)結(jié)構(gòu),如何更好的簡化它呢?
// 建立測試集合 List<Integer> list = Arrays.asList(1, 2, 2, 3, 4, 5, 5, 6); // 基礎(chǔ)循環(huán) System.out.println("----------------------------1 基礎(chǔ)循環(huán)"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } // 語法糖方式 System.out.println("----------------------------2 迭代器語法糖"); for (Integer i : list) { System.out.println(i); } // lambda 表達(dá)式簡寫 System.out.println("----------------------------3 lambda"); list.forEach(item -> System.out.println(item)); // 使用lambda 方法引用 System.out.println("----------------------------4 lambda"); list.forEach(System.out::println);// 以下為編譯后語法糖的代碼 Iterator var4 = list.iterator(); while(var4.hasNext()) { Integer i = (Integer)var4.next(); System.out.println(i); }從上面的代碼我們可以看出,隨著 lambda 方式的引入,代碼變得越來越簡化,而且更加容易讀懂,寫的東西也越來越少,
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
第一種方式則是我們常規(guī)的操作方式,一般適用于需要 下標(biāo) 邏輯的業(yè)務(wù)中。
第二種則是迭代器語法糖,對于開發(fā)者而言寫起來便捷,不過對于代碼的編譯而言,編譯后的代碼任是迭代器的方式,只不過語法簡單了。
lambda 則是一種函數(shù)式的表達(dá)方式,item 作為我們循環(huán)的參數(shù),而箭頭后則是我們需要執(zhí)行的代碼塊,一句代碼完全不必使用 {}
lambda 方法引用 則是一種全新的方式, 引用 二字經(jīng)常被我們使用,一般在對象的引用處有表達(dá)的含義,簡而言之就是 一個(gè)值可以從一個(gè)地方引用過來使用 ,但是現(xiàn)在,方法完全可以被看做一個(gè) 值 一樣,也可以隨意拿過來使用~
可能朋友們就會(huì)有疑惑,為什么 forEach 的地方就可以使用 lambda 表達(dá)式呢,其他地方怎么不行?我們來看看源碼
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }我們發(fā)現(xiàn) Consumer 是一個(gè)接口,內(nèi)部仍然使用 for語法糖 形式來執(zhí)行集合,調(diào)用了 accept 方法。
消費(fèi)者接口,適用于入?yún)⑻幚恚瑹o返回值
@FunctionalInterface public interface Consumer<T> { void accept(T t);發(fā)現(xiàn)這個(gè)接口和其他接口唯一的不同點(diǎn)就是 @FunctionalInterface
其實(shí)這個(gè)注解就是來告訴編譯器,這個(gè)接口下的 accept 方法可以使用函數(shù)式寫法來描述。有了這個(gè)注解的定義,我們就可以愉快的使用函數(shù)式lambda 表達(dá)式了。
消費(fèi)者接口 作為JDK 自帶的函數(shù)式接口,所處于 java.util.function 包下,并且支持鏈?zhǔn)讲僮鳎?/p>
接受一個(gè)指定的泛型,內(nèi)部處理后,無返回值
// 無返回的處理 Consumer<String> custom = (str) -> System.out.println("first" + str); Consumer<String> desc = custom.andThen((str) -> System.out.println("second" + str)); desc.accept("hello"); -------------------------- firsthello secondhello稍稍總結(jié)一下lambda 的基礎(chǔ)語法:
(參數(shù))-> 一行執(zhí)行代碼
(參數(shù))-> {多行執(zhí)行代碼}
默認(rèn)實(shí)現(xiàn),子類無需重寫接口定義的關(guān)鍵詞
上面的Consumer使用中,我們發(fā)現(xiàn),有一個(gè)默認(rèn)實(shí)現(xiàn)的接口,順便來說明一下
default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }default 提供默認(rèn)的實(shí)現(xiàn)方式,實(shí)現(xiàn)類無需重寫這個(gè)方法的定義,而可以直接使用。
把方法也可以作為值一樣來引用使用。
// 使用lambda 方法引用 System.out.println("----------------------------4 lambda"); list.forEach(System.out::println);博主這里的理解是:引用的方法需要與定義處: default void forEach(Consumer<? super T> action)
所需要的lambda 表達(dá)式具有相同的入?yún)€(gè)數(shù)與返回類型,才可以引用。
例如: Consumer 接口接受的lambda 形式為: item -> System.out.println(item)
而我們引用的 System.out::println 剛好具備這樣的形式。
public void println(Object x) { String s = String.valueOf(x); synchronized (this) { print(s); newLine(); } }我們都知道,JAVA 里面最討厭的一個(gè)異常就是 NPE=NullPointerException 空指針異常,為了避免空指針異常,我們經(jīng)常不少使用 if 作為判斷,這樣的判斷多了就容易讓人看著惱火。例如如下代碼:
Person person = new Person("test", 1); if (person != null) { if (person.getName() != null) { System.out.println("123" + person.getName()); } else { // do something } } else { // do something }假設(shè)我們有一個(gè) person 對象,首先判斷它是否為空,如果不為空,則取值,而后再獲取 name 成員變量,不為空則拼接打印。這樣兩層判斷的邏輯在代碼里經(jīng)常會(huì)見到,學(xué)習(xí)了 Optional 以后,我們的以上邏輯就可以修改為如下:
// 最佳實(shí)踐 Optional.ofNullable(person).map(p -> p.getName()).map(string -> string.concat("123")).ifPresent(System.out::println);入?yún)⒉⒎祷匾粋€(gè)指定類型,可以理解為轉(zhuǎn)換。
首先發(fā)現(xiàn) map 接受一個(gè) Function<? super T, ? extends U> mapper ,具體如何使用Function
@FunctionalInterface public interface Function<T, R> { R apply(T t);// 鏈?zhǔn)睫D(zhuǎn)換 Function<String,Integer> stringToInteger = Integer::valueOf; // andThen 將前一個(gè)處理的返回值作為后一個(gè)處理的入?yún)?nbsp;Function<String,String> integerToString = stringToInteger.andThen(Integer::toHexString); String hex = integerToString.apply("123"); System.out.println(hex);// 7b優(yōu)雅判斷空,并且執(zhí)行對應(yīng)操作
Optional 對于 NPE 有著很好的解決方式,可以解決我們多重if 的優(yōu)化,不僅美觀,而且非常優(yōu)雅。
// 如果person 為null 則觸發(fā)異常 Optional.of(person); // 如果person1 為 null 則返回empty Optional.ofNullable(person1);
以上是創(chuàng)建實(shí)例的兩種方式,一般常用第二種,第一種如果有 null 的情況則會(huì)觸發(fā) NPE 到頭來還是沒有處理掉這個(gè)異常,所以不建議使用。
private Optional() { this.value = null; }isPresent(): 如果不為空則返回true。 get(): 獲取當(dāng)前包含的值,若是value=null 則拋出NPE orElse(T other): 如果當(dāng)前實(shí)例包含值為null,則返回other; ifPresent(Consumer<? super T> consumer): 若當(dāng)前實(shí)例不為空,則執(zhí)行這個(gè)消費(fèi)者consumer,否則返回EMPTY
stream 作為 JAVA8 最核心的內(nèi)容,融匯貫通的掌握其精髓,對開發(fā)者而言,無非是一把打開新世界大門的鑰匙。從宏觀的角度來講,一個(gè)語言處理最多的就是數(shù)據(jù)的集合,比如 List<?>
過濾器,過濾出你想要的集合元素。
List<Integer> list = Arrays.asList(1, 2, 3, 3, 4, 5, 5, 6); // 篩選偶數(shù) long num = list.stream().filter(item -> item % 2 == 0).count(); // 3
這里通過簡單的篩選,篩選的條件是偶數(shù),并且最終統(tǒng)計(jì)它的個(gè)數(shù)。
這里的 filter 接受一個(gè) filter(Predicate<? super T> predicate)
count 簡而言之了,就是統(tǒng)計(jì)前方表達(dá)式所產(chǎn)生的新集合個(gè)數(shù)。
斷言,也是一個(gè)函數(shù)式接口,可以使用lambda 表達(dá)式。
@FunctionalInterface public interface Predicate<T> { boolean test(T t);Predicate 主要實(shí)現(xiàn)其 test 接口,通過邏輯執(zhí)行,返回一個(gè) boolean 來判斷當(dāng)前元素是否可用。
// 斷言字符串長度大于0 Predicate<String> stringEmpty = (str) -> str.length() > 0; Predicate<String> startHello = (str) -> str.startsWith("hello"); System.out.println("test 空字符=" + stringEmpty.test("")); System.out.println("test hello=" + stringEmpty.test("hello")); // and 合并兩個(gè)檢驗(yàn)接口,同時(shí)滿足即可 or 只要有一個(gè)滿足即可 System.out.println("test and hello world=" + stringEmpty.and(startHello).test("hello world")); System.out.println("test or world=" + stringEmpty.or(startHello).test("world")); ---------------------- test 空字符=false test hello=true test and hello world=true test or world=truemap 可以理解為映射,處理每個(gè)元素,并且返回任何類型。支持鏈?zhǔn)絤ap,
上層map的返回值作為下層map的參數(shù)值。
List<Person> people = Arrays.asList(new Person("hello", 1), new Person("world", 2)); // 將每一個(gè)元素的name 組裝成一個(gè)新的集合。 List<String> names = people.stream().map(item -> item.getName()).collect(Collectors.toList()); System.out.println(names); // 多重map處理 List<String> concat = people.stream().map(item -> item.getName()).map(name -> name.concat("-concat")).collect(Collectors.toList()); System.out.println(concat); ------------------- [hello, world] [hello-concat, world-concat]map 接受一個(gè) map(Function<? super T, ? extends R> mapper) 我們上面已經(jīng)討論過這個(gè)了。
對元素進(jìn)行排序,可以使用默認(rèn),也可以自定義排序規(guī)則。
List<String> sortedList = Arrays.asList("acc", "dee", "zdd", "wee", "abb", "ccd"); // 默認(rèn)排序,字典順序,第一個(gè)字母相同,則比較第二個(gè) List<String> sorted = sortedList.stream().sorted().collect(Collectors.toList()); System.out.println(sorted); // 自定義實(shí)現(xiàn),只比較第一個(gè)字符 List<String> sorted2 = sortedList.stream().sorted((str1, str2) -> str1.charAt(1) - str2.charAt(1)).collect(Collectors.toList()); System.out.println(sorted2); --------------------------- [abb, acc, ccd, dee, wee, zdd] // 可以發(fā)現(xiàn)自定義的排序沒有比較第二個(gè)字母 [acc, abb, ccd, dee, wee, zdd]我們發(fā)現(xiàn) sorted 接受一個(gè) Comparator<? super T> comparator
比較器,也是函數(shù)式接口,不必多說,自然可以使用lambda
@FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2);Comparator<String> comparator = (str1, str2) -> str1.charAt(0) - str2.charAt(0); // 自定義比較第一位字母 int a = comparator.compare("abb", "acc"); System.out.println(a); // 再次比較,如果第一個(gè)返回0,則直接返回結(jié)果,否則進(jìn)行二次比較 int b = comparator.thenComparing((str1, str2) -> str1.charAt(1) - str2.charAt(1)).compare("abb", "acc"); System.out.println(b); ------------------------------ 0 -1比較器返回一個(gè)int 值,這個(gè)int 則表示兩個(gè)元素的排列順序,按照 ASCII表 指示的值大小,如果兩個(gè)元素的差值 a-b>0 則 a在前,b在后
同樣,Match 用來處理當(dāng)前序列中,全部滿足、或者部分滿足,返回一個(gè)布爾值
List<String> sortedList = Arrays.asList("acc", "dee", "zdd", "wee", "abb", "ccd"); // 所有的元素都斷言通過,就返回true,否則false boolean startWithA = sortedList.stream().allMatch(str -> str.startsWith("a")); System.out.println(startWithA); // 只要有一個(gè)滿足就返回true boolean hasA = sortedList.stream().anyMatch(str -> str.startsWith("a")); System.out.println(hasA); ------------------------ false true以上就是 stream 常用的一些總結(jié),總結(jié)了一些非常常用的,未總結(jié)到的內(nèi)容下期補(bǔ)充。
這里提一下局部變量final 語義。
模仿以上的任意一個(gè)函數(shù)接口,我們可以寫出這樣的一個(gè)轉(zhuǎn)換接口,將指定類型轉(zhuǎn)換為指定類型
@FunctionalInterface public interface FunctionInterface<A, R> { R cover(A t); }通過自定義函數(shù)接口,我們可以寫出如下代碼,來進(jìn)行轉(zhuǎn)換,不過涉及到一些參數(shù)的改變。
// num 局部變量如果在lambda 中使用,則隱式含有final 語義 final int num = 1; FunctionInterface<String, Integer> function4 = (val) -> Integer.valueOf(val + num); Integer result4 = function4.cover("12"); // num = 2; // 這里不能改變,修改則不能通過編譯到此,關(guān)于“JAVA 8新特性有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
網(wǎng)站欄目:JAVA8新特性有哪些
瀏覽地址:http://www.chinadenli.net/article0/igpdoo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、商城網(wǎng)站、網(wǎng)站維護(hù)、網(wǎng)站導(dǎo)航、網(wǎng)站策劃、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)