乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      java8新特性,你有用起來了嗎?(精編)

       行者花雕 2022-01-31
       

      2019年9月19日java13已正式發(fā)布,感嘆java社區(qū)強大,經(jīng)久不衰。由于國內(nèi)偏保守,新東西總要放一放,讓其他人踩踩坑,等穩(wěn)定了才會去用。并且企業(yè)目的還是賺錢,更不會因為一個新特性去重構(gòu)代碼,再開發(fā)一套程序出來。甚者國內(nèi)大多傳統(tǒng)企業(yè)還在用java4 、5、6…


      今天講一講 java8 的新特性,Java 8 (又稱為 jdk 1.8) 是 Java 語言開發(fā)的一個主要版本。Oracle 公司于 2014 年 3 月 18 日發(fā)布 Java 8 ,它支持函數(shù)式編程,新的日期 API,新的Stream API 等。是Java5之后一個大的版本升級,讓Java語言和庫仿佛獲得了新生,核心新特性包含:

      • Java8 函數(shù)式接口? 函數(shù)式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。函數(shù)式接口可以被隱式轉(zhuǎn)換為 lambda 表達式。

      • Lambda 表達式 ? Lambda 允許把函數(shù)作為一個方法的參數(shù)(函數(shù)作為參數(shù)傳遞到方法中)。

      • 默認方法 ? 默認方法就是一個在接口里面有了一個實現(xiàn)的方法。

      • 方法引用 ? 方法引用提供了非常有用的語法,可以直接引用已有Java類或?qū)ο螅▽嵗┑姆椒ɑ驑?gòu)造器。與lambda聯(lián)合使用,方法引用可以使語言的構(gòu)造更緊湊簡潔,減少冗余代碼。

      • Stream API ?新添加的Stream API(java.util.stream) 把真正的函數(shù)式編程風格引入到Java中。

      • Date Time API ? 加強對日期與時間的處理。

      • Optional 類 ? Optional 類已經(jīng)成為 Java 8 類庫的一部分,用來解決空指針異常。


      一. 函數(shù)式接口

      函數(shù)式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。
      函數(shù)式接口可以被隱式轉(zhuǎn)換為 lambda 表達式。

      JDK 1.8 之前已有的函數(shù)式接口:

      java.lang.Runnable
      java.util.concurrent.Callable
      java.security.PrivilegedAction
      java.util.Comparator
      java.io.FileFilter
      java.nio.file.PathMatcher
      java.lang.reflect.InvocationHandler
      java.beans.PropertyChangeListener
      java.awt.event.ActionListener
      javax.swing.event.ChangeListener

      JDK 1.8 新增加的函數(shù)接口:

      java.util.function

      這里說一下@FunctionalInterface注解,這個注解是java8新出得一個注解。

      我們常用的一些接口Callable、Runnable、Comparator等在JDK8中都添加了@FunctionalInterface注解。
      在這里插入圖片描述

      追蹤源碼查看@FunctionalInterface注解javadoc

      在這里插入圖片描述通過JDK8源碼javadoc,可以知道這個注解有以下特點:

      • 該注解只能標記在”有且僅有一個抽象方法”的接口上。

      • JDK8接口中的靜態(tài)方法和默認方法,都不算是抽象方法。

      • 接口默認繼承Java.lang.Object,所以如果接口顯示聲明覆蓋了Object中方法,那么也不算抽象方法。

      • 該注解不是必須的,如果一個接口符合”函數(shù)式接口”定義,那么加不加該注解都沒有影響。加上該注解能夠更好地讓編譯器進行檢查。如果編寫的不是函數(shù)式接口,但是加上了@FunctionInterface,那么編譯器會報錯。

      @FunctionalInterface標記在接口上,“函數(shù)式接口”是指僅僅只包含一個抽象方法的接口。
      在這里插入圖片描述

      如果一個接口中包含不止一個抽象方法,那么不能使用@FunctionalInterface,編譯會報錯。

      在這里插入圖片描述

      比如下面這個接口就是一個正確的函數(shù)式接口:
      在這里插入圖片描述


      二. 默認方法

      簡單說,默認方法就是接口可以有實現(xiàn)方法,而且不需要實現(xiàn)類去實現(xiàn)其方法。

      我們只需在方法名前面加個 default 關鍵字即可實現(xiàn)默認方法。

      為什么要有這個特性?

      首先,之前的接口是個雙刃劍,好處是面向抽象而不是面向具體編程,缺陷是,當需要修改接口時候,需要修改全部實現(xiàn)該接口的類,目前的 java 8 之前的集合框架沒有 foreach 方法,通常能想到的解決辦法是在JDK里給相關的接口添加新的方法及實現(xiàn)。然而,對于已經(jīng)發(fā)布的版本,是沒法在給接口添加新方法的同時不影響已有的實現(xiàn)。所以引進的默認方法。他們的目的是為了解決接口的修改與現(xiàn)有的實現(xiàn)不兼容的問題。

      這里值得注意的是,我們知道java中一個類可以實現(xiàn)多個接口 如果多個接口中有同名同參同返回值得默認方法需要我們在實現(xiàn)類重寫該方法,否則會編譯報錯。


      三. lambda表達式

      這是java8的一大重要特性,我們知道java是面向?qū)ο笳Z言,把行為封裝成一個對象是我們根深蒂固的java編程思想,但是lambda正好反其道而行之,是一種面向過程的編程思想。

      不在贅述更多模糊,概念的含義,大家現(xiàn)在有這樣的一個認識就可以了。下面我會用例子帶入大家。
      能夠接收Lambda表達式的參數(shù)類型,是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口?!昂瘮?shù)接口”??梢皂斕婺涿麅?nèi)部類。

      語法:

      (parameters) -> expression或(parameters) ->{ statements; }

      以下是lambda表達式的重要特征:

      • 可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識別參數(shù)值。

      • 可選的參數(shù)圓括號:一個參數(shù)無需定義圓括號,但多個參數(shù)需要定義圓括號。

      • 可選的大括號:如果主體包含了一個語句,就不需要使用大括號。

      • 可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數(shù)值。

      老版本Java中排列字符串

      
      Collections.sort(names, new Comparator<String>() {
          @Override
          public int compare(String a, String b) {
              return b.compareTo(a);
          }
      });
       

      只需要給靜態(tài)方法 Collections.sort 傳入一個List對象以及一個比較器來按指定順序排列。通常做法都是創(chuàng)建一個匿名的比較器對象然后將其傳遞給sort方法。

      在Java 8 中你就沒必要使用這種傳統(tǒng)的匿名對象的方式了,直接上lambda

      Collections.sort(names, (String a, String b) -> {
          return b.compareTo(a);
      });
       

      看到了吧,代碼變得更段且更具有可讀性,但是實際上還可以寫得更短:

      Collections.sort(names, (String a, String b) -> b.compareTo(a));
       

      對于函數(shù)體只有一行代碼的,你可以去掉大括號{}以及return關鍵字,但是你還可以寫得更短點:

      Collections.sort(names, (a, b) -> b.compareTo(a));
       

      據(jù)官方文檔中介紹Java編譯器可以自動推導出參數(shù)類型,可以不寫,但是這里我還是建議大家寫出參數(shù)類型,方便代碼被其他人閱讀時候的可讀性。自己反過來查看代碼也有幫助。


      總結(jié):

      缺點 : 學習成本稍高,剛開始接觸不容易理解,并需要反復練習。

      優(yōu)點 : lambda表達式讓我們可以把一個方法當成參數(shù)傳遞進另一個方法,頂替匿名內(nèi)部類消除了樣板式代碼。并讓我們的代碼看起來更加簡潔、干凈。

      并且lambda表達式可以在結(jié)合很多地方使用。下面涉及我會再分析??偟膩碚flambda表達式還是值得我們學習的。


      四. stream流

      Java 8 API添加了一個新的抽象稱為流Stream,可以讓你以一種聲明的方式處理數(shù)據(jù)。

      Stream 使用一種類似用 SQL 語句從數(shù)據(jù)庫查詢數(shù)據(jù)的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。

      Stream API可以極大提高Java程序員的生產(chǎn)力,讓程序員寫出高效率、干凈、簡潔的代碼。

      這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 并且可以在管道的節(jié)點上進行處理, 比如篩選, 排序,聚合等。

      元素流在管道中經(jīng)過中間操作(intermediate operation)的處理,最后由最終操作(terminal operation)得到前面處理的結(jié)果。

      什么是stream?

      Stream(流)是一個來自數(shù)據(jù)源的元素隊列并支持聚合操作。

      元素是特定類型的對象,形成一個隊列。Java中的Stream并不會存儲元素,而是按需計算。

      數(shù)據(jù)源 流的來源??梢允羌希瑪?shù)組,I/O channel, 產(chǎn)生器generator 等。

      聚合操作 類似SQL語句一樣的操作, 比如filter, map, reduce, find, match, sorted等。

      和以前的Collection操作不同, Stream操作還有兩個基礎的特征:

      Pipelining: 中間操作都會返回流對象本身。這樣多個操作可以串聯(lián)成一個管道, 如同流式風格(fluent style)。這樣做可以對操作進行優(yōu)化, 比如延遲執(zhí)行(laziness)和短路( short-circuiting)。

      內(nèi)部迭代:以前對集合遍歷都是通過Iterator或者For-Each的方式, 顯式的在集合外部進行迭代, 這叫做外部迭代。Stream提供了內(nèi)部迭代的方式, 通過訪問者模式(Visitor)實現(xiàn)。

      在 Java 8 中, 集合接口有兩個方法來生成流:

      stream() ? 為集合創(chuàng)建串行流。

      parallelStream() ? 為集合創(chuàng)建并行流。

      在這里插入圖片描述

      API:

      forEach() Stream 提供了新的方法 'forEach’ 來迭代流中的每個數(shù)據(jù),以下代碼片段使用 forEach 輸出了10個隨機數(shù):

      在這里插入圖片描述

      limit() 方法用于獲取指定數(shù)量的流,以下代碼片段使用 limit 方法打印出 10 條數(shù)據(jù):

      在這里插入圖片描述

      map() 方法用于映射每個元素到對應的結(jié)果, 以下代碼片段使用 map 輸出了元素對應的平方數(shù):
      distinct() 去重 需要實現(xiàn)hascCode和equase方法

      在這里插入圖片描述

      filter() 方法用于通過設置的條件過濾出元素。以下代碼片段使用 filter 方法過濾出空字符串:

      在這里插入圖片描述

      sorted 方法用于對流進行排序。以下代碼片段使用 sorted 方法對輸出的 10 個隨機數(shù)進行排序:

      在這里插入圖片描述

      并行(parallel)程序

      parallelStream 是流并行處理程序的代替方法。以下實例我們使用 parallelStream 來輸出空字符串的數(shù)量:

      在這里插入圖片描述

      Collectors 結(jié)合 collect()方法后使用 Collectors.joining(String 分隔符) Collectors.toList()變?yōu)榧?br>Collectors 類實現(xiàn)了很多歸約操作,例如將流轉(zhuǎn)換成集合和聚合元素。Collectors 可用于返回列表或字符串:
      在這里插入圖片描述


      五. 方法引用

      方法引用通過方法的名字來指向一個方法。

      方法引用可以使語言的構(gòu)造更緊湊簡潔,減少冗余代碼。

      方法引用使用一對冒號 :: 。

      下面,我們在 Car 類中定義了 4 個方法作為例子來區(qū)分 Java 中 4 種不同方法的引用。

      在這里插入圖片描述

      構(gòu)造器引用:它的語法是Class::new,或者更一般的Class< T >::new實例如下:

            finalCarcar=Car.create(Car::new);
      
            finalList<Car>cars=Arrays.asList(car);
       

      靜態(tài)方法引用:它的語法是Class::static_method,實例如下:

            cars.forEach(Car::collide);
       

      特定類的任意對象的方法引用:它的語法是Class::method實例如下:

            cars.forEach(Car::repair);
       

      特定對象的方法引用:它的語法是instance::method實例如下:

            finalCarpolice = Car.create(Car::new);
      
                   cars.forEach(police::follow);
       

      方法引用實例
      在 Java8Tester.java 文件輸入以下代碼:
      在這里插入圖片描述

      實例中我們將 System.out::println 方法作為靜態(tài)方法來引用。

      執(zhí)行以上腳本,輸出結(jié)果為:

      在這里插入圖片描述


      六. 日期時間 API

      Java 8通過發(fā)布新的Date-Time API (JSR 310)來進一步加強對日期與時間的處理。

      因為Java的Date,Calendar類型使用起來并不是很方便,而且Date類(據(jù)說)有著線程不安全等諸多弊端。同時若不進行封裝,會在每次使用時特別麻煩。于是Java8推出了線程安全、簡易、高可靠的時間包。并且數(shù)據(jù)庫中也支持LocalDateTime類型,在數(shù)據(jù)存儲時候使時間變得簡單。Java8這次新推出的包括三個相關的時間類型:LocalDateTime年月日十分秒;LocalDate日期;LocalTime時間;三個包的方法都差不多。

      列出常用api,詳細的使用網(wǎng)上大片,大家自行查找:

      //獲取當前時間的LocalDateTime對象
      //LocalDateTime.now();
      
      //根據(jù)年月日構(gòu)建LocalDateTime
      //LocalDateTime.of(); 
      
      //比較日期先后
      //LocalDateTime.now().isBefore(),
      //LocalDateTime.now().isAfter(),
       

      七. Optional 類

      Optional不是對null關鍵字的一種替代,而是對于null判定提供了一種更加優(yōu)雅的實現(xiàn)。

      NullPointException可以說是所有java程序員都遇到過的一個異常,雖然java從設計之初就力圖讓程序員脫離指針的苦海,但是指針確實是實際存在的,而java設計者也只能是讓指針在java語言中變得更加簡單、易用,而不能完全的將其剔除,所以才有了我們?nèi)粘K姷降年P鍵字null。

      空指針異常是一個運行時異常,對于這一類異常,如果沒有明確的處理策略,那么最佳實踐在于讓程序早點掛掉,但是很多場景下,不是開發(fā)人員沒有具體的處理策略,而是根本沒有意識到空指針異常的存在。

      當異常真的發(fā)生的時候,處理策略也很簡單,在存在異常的地方添加一個if語句判定即可,但是這樣的應對策略會讓我們的程序出現(xiàn)越來越多的null判定,我們知道一個良好的程序設計,應該讓代碼中盡量少出現(xiàn)null關鍵字,而java8所提供的Optional類則在減少NullPointException的同時,也提升了代碼的美觀度。但首先我們需要明確的是,它并 不是對null關鍵字的一種替代,而是對于null判定提供了一種更加優(yōu)雅的實現(xiàn),從而避免NullPointException。

      1). 直觀感受

      假設我們需要返回一個字符串的長度,如果不借助第三方工具類,我們需要調(diào)用str.length()方法:

      if(null == str) { // 空指針判定
      
      return 0;
      
      }
      
      return str.length();
       

      如果采用Optional類,實現(xiàn)如下:

      return Optional.ofNullable(str).map(String::length).orElse(0)

      Optional的代碼相對更加簡潔,當代碼量較大時,我們很容易忘記進行null判定,但是使用Optional類則會避免這類問題。

      2). 基本使用
      1.對象創(chuàng)建
      Optional<String> optStr = Optional.empty();

      上面的示例代碼調(diào)用empty()方法創(chuàng)建了一個空的Optional對象型。

      創(chuàng)建對象:不允許為空
      Optional提供了方法of()用于創(chuàng)建非空對象,該方法要求傳入的參數(shù)不能為空,否則拋NullPointException,示例如下:

      // 當str為null的時候,將拋出NullPointException
      Optional<String> optStr = Optional.of(str);
      2. 創(chuàng)建對象:允許為空
      如果不能確定傳入的參數(shù)是否存在null值的可能性,則可以用Optional的ofNullable()方法創(chuàng)建對象,如果入?yún)閚ull,則創(chuàng)建一個空對象。示例如下:
      // 如果str是null,則創(chuàng)建一個空對象
      Optional<String> optStr = Optional.ofNullable(str);
      3.流式處理
      流式處理也是java8給我們帶來的一個重量級新特性,讓我們對集合的操作變得更加簡潔和高效。

      這里Optional也提供了兩個基本的流失處理:映射和過濾。

      為了演示,我們設計了一個User類,如下:

      public class User {
      
      
      /** 用戶編號 */
      
      private long id;
      
      private String name;
      
      private int age;
      
      private Optional<Long> phone;
      
      private Optional<String> email;
      
      public User(String name, int age) {
      
      this.name = name;
      
      this.age = age;
      
      }
      
      
      // 省略setter和getter
      
      }
       

      手機和郵箱不是一個人的必須有的,所以我們利用Optional定義。

      映射:map與flatMap

      映射是將輸入轉(zhuǎn)換成另外一種形式的輸出的操作

      比如前面例子中,我們輸入字符串,而輸出的是字符串的長度,這就是一種隱射,我們利用方法map()得以實現(xiàn)。假設我們希望獲得一個人的姓名,那么我們可以如下實現(xiàn):

      String name = Optional.ofNullable(user).map(User::getName).orElse("no name");
       

      這樣當入?yún)ser不為空的時候則返回其name,否則返回no name

      如果我們希望通過上面方式得到phone或email,利用上面的方式則行不通了,因為map之后返回的是Optional,我們把這種稱為Optional嵌套,我們必須在map一次才能拿到我們想要的結(jié)果:

      long phone = optUser.map(User::getPhone).map(Optional::get).orElse(-1L);
       

      其實這個時候,更好的方式是利用flatMap,一步拿到我們想要的結(jié)果:

      long phone = optUser.flatMap(User::getPhone).orElse(-1L);
      過濾:fliter

      iliter,顧名思義是過濾的操作,我們可以將過濾操作做為參數(shù)傳遞給該方法,從而實現(xiàn)過濾目的

      假如我們希望篩選18周歲以上的成年人,則可以實現(xiàn)如下:

      optUser.filter(u -> u.getAge() >= 18).ifPresent(u -> System.out.println("Adult:" + u));
      4.默認行為

      默認行為是當Optional為不滿足條件時所執(zhí)行的操作,比如在上面的例子中我們使用的orElse()就是一個默認操作,用于在Optional對象為空時執(zhí)行特定操作,當然也有一些默認操作是當滿足條件的對象存在時執(zhí)行的操作。

      get()

      get用于獲取變量的值,但是當變量不存在時則會拋出NoSuchElementException,所以如果不確定變量是否存在,則不建議使用


      orElse(Tother)

      當Optional的變量不滿足給定條件時,則執(zhí)行orElse,比如前面當str為null時,返回0。


      orElseGet(Supplier<? extends X> expectionSupplier)

      如果條件不成立時,需要執(zhí)行相對復雜的邏輯,而不是簡單的返回操作,則可以使用orElseGet實現(xiàn):

      long phone = optUser.map(User::getPhone).map(Optional::get).orElseGet(() -> {
      
      // do something here
      
      return -1L;
      
      });

       orElseThrow(Supplier<? extends X> expectionSupplier)

      與get()方法類似,都是在不滿足條件時返回異常,不過這里我們可以指定返回的異常類型。


      ifPresent(Consumer<? super T>)

      當滿足條件時執(zhí)行傳入的參數(shù)化操作。


      3). 注意事項

      Optional是一個final類,未實現(xiàn)任何接口,所以當我們在利用該類包裝定義類的屬性的時候,如果我們定義的類有序列化的需求,那么因為Optional沒有實現(xiàn)Serializable接口,這個時候執(zhí)行序列化操作就會有問題:

      public class User implements Serializable{
      
      
      /** 用戶編號 */
      
      private long id;
      
      private String name;
      
      private int age;
      
       private Optional<Long> phone;  // 不能序列化
      
      private Optional<String> email;  // 不能序列化
      
      不過我們可以采用如下替換策略:
      
      private long phone;
      
      public Optional<Long> getPhone() {
      
      return Optional.ofNullable(this.phone);
      
      }

      今天分享到此結(jié)束,通過本篇文章了解java8的新特性不僅強大而且感覺很多地方都能馬上使用起來,比如通過stream流處理集合數(shù)據(jù)結(jié)合lambda寫出高效、干凈、簡潔的代碼,通過Optional類優(yōu)雅的處理NPE。rd們裝X的最高境界就是寫一手其他rd們看不懂又覺得很高大上的代碼了吧。哈哈哈。。。本著學習的態(tài)度,如果文章內(nèi)有出入地方請指出,看到留言后我會和大家討論學習。

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多