Java 8 不止是Lambdas和Streams

來源:互聯網
上載者:User

標籤:msu   對象   reduce   工程   now()   public   安全執行緒   final   des   

轉眼淘系應用升級JDK8已經幾個月過去了,Lambdas運算式和Streams APIs的確給同學們帶來了編程效率和代碼可讀性上的提升,代碼變得更加簡潔直接,更加符合人的思維(看來程式設計語言的發展也是本著“以人為本”的思路)。ATA上講這兩個新特性的文章已經很多了, 大魚大肉大家吃的差不多,得常常家常小菜吧,下面總結一下常用的Java 8中Lambdas和Streams之外的一些新特性。

1. Default Method

Java 單繼承的特性決定了一個類只能有1個父類,如果有通用的方法實現就只能寫在父類裡,如果是介面就不能有實現,偏偏Java 8中的stream方法就遇到了這個問題。原來沒有吧,在Collection介面裡加個非defaultstream方法,必須在所有實現介面的類中都要實現這個方法(難道他們真的把XXXListXXXSet都改了?)

肯(bu)定(yao)沒(sha)有(le),Oracle猿們開了個後門(自己的東西就是方便,自己想改就改),他們用default method解決了這個問題。在Collection介面中實現了一個default method - stream, 這樣所有其他的XXXList都不用改了,還可以直接使用這個方法。當然,只要實作類別中不重寫這個方法,執行個體調用的就是介面中的實現。

可以看到java.util.Collection中確實加了3個default方法。

default Spliterator<E> spliterator() {        return Spliterators.spliterator(this, 0);}default Stream<E> stream() {        return StreamSupport.stream(spliterator(), false);}default Stream<E> parallelStream() {        return StreamSupport.stream(spliterator(), true);}

使用上其實就是default關鍵字,在interface的方法上加上default就會有2個作用:a. 介面中必須實現這個方法;b. 子類中可以不實現這個方法了。
另外,還可以在interface中加入static方法,配合default使用,這樣直接靜態方式使用介面的default方法,減少了寫一些另外的util/helper類。

// 介面類public interface BaseJava {    default void sayHi(){        System.out.println("Hi default method");    }    public void goodbye();}// 實作類別public class ChildJava implements BaseJava{    @Override    public void goodbye() {        System.out.println("必須實現的方法");    }    public static void main(String...args){        ChildJava cj = new ChildJava();        cj.sayHi(); // default method    }}
2. Optional

業務應用的對象往往比較大,對象裡面有對象,對象裡面還有對象...在處理的時候,總是得判斷是否為null,這無形增加了程式的判斷深度(如果不加判斷,就是NullPointerException了,關鍵是一旦出了異常,排查起來也是時間)

如果是這種普通的非空判斷(用isPresent()代替!=null),其實和以前差不多,好像沒有怎麼方便(個人感覺甚至麻煩了,實際上相當於把非空判斷封裝了一個Helper靜態方法)。

Optional<String> str = Optional.ofNullable("some returned value"); // 可能是空System.out.println(str.isPresent()?str.get():"default value"); // Java 8System.out.println(str.orElse("default value")); // Java 8System.out.println(str!=null?str:"default value"); // Java 7// 看看Java原始碼public boolean isPresent() {        return value != null;}public T orElse(T other) {        return value != null ? value : other;}

但是,在對象比較複雜的情況下,就顯得比較高效了,尤其是配合stream (reduce max min)和 lambdas表達使用。看到傳回值是Optional的情況下,都會下意識去判斷非空,這和之前相比,可以減少程式因為NullPointerException而出現的功能缺陷,提高開發效率(我記得google的一個三方包裡早就有Optional這個東東了)。

3. 字串API

Scenario 1. 業務應用處理最多的東西莫過於List和String,常見的操作就是給你一個List,處理一下串成一個String,或者給你一個String(用delimiter分隔的),處理一下變成一個List(木辦法,前端要String ,後端要List,夾在中間只能不停地ForEach了)

這要擱以前(Java 7),某猿會這樣寫:

// 1 給前端拼一個逗號分隔的商品id列表的字串List<String> itemIdList = ...; // 從IC擷取的熱乎乎的ListStringBuffer sb = new StringBuffer();  // 也可以用StringBuilder...for(String itemId: itemIdList){        sb.append(itemId).append(","); // TODO  BUG 末尾還有一個 ,}return sb.toString();        // 2 前端傳來的都好分隔的商品id列表字串,咱轉成List給後端String str ="1000,1001,1002,1003";String[] arr=str.split(",");List<String> list = Arrays.asList(arr);

這樣寫當然沒問題,但是在商務邏輯處理中,老是來這麼一下,一則影響代碼美觀(本來類像一棵直挺挺的樹,加了幾個這個,像是樹瘤一樣,100行代碼中有50行是for迴圈...),二則容易打斷了主要商務邏輯的思路(轉而處理for迴圈裡面的內容,當心最後一個 , )。

使用Java 8以後,情況會好很多,一兩行代碼搞定:

// 1 給前端拼一個逗號分隔的商品id列表的字串List<String> itemIdList = ...; return String.join(",", itemIdList);// 當然,如果擷取的是Object,就需要配合streams來完成join了List<ItemDO> itemDOs = ...String names = itemDOs.stream().map(ItemDO::getItemId).collect(Collectors.joining(","));// java 8 源碼 String.join的實現public static String join(CharSequence delimiter, CharSequence... elements) {    Objects.requireNonNull(delimiter);    Objects.requireNonNull(elements);    // Number of elements not likely worth Arrays.stream overhead.    StringJoiner joiner = new StringJoiner(delimiter);    for (CharSequence cs: elements) {        joiner.add(cs);    }    return joiner.toString();}
4. 日期和時間API

Scenario 2. 業務應用總是免不了和日期時間打交道,而且,與多個系統對接後,要在日期、時間、日期時間、字串等來回倒騰,前端要字串,資料庫存的datetime, 兄弟團隊的二方包居然只要日期部分的String等等,當然還有日期的操作,向前多少天,向後多少天

Java 7當中,我們最長使用的莫過於Calendar了,因為它簡單輕便,而且支援日期操作。此外,配合SimpleDateFormat, 就可以把任何String轉換成日期,然後利用Calendar操作,最後再使用另一個SimpleDateFormat寫成前端需要的格式。通常情況下,這樣寫:

SimpleDateFormat sdf =new SimpleDateFormat("yyyy/MM/dd");SimpleDateFormat sdf2 =new SimpleDateFormat("yyyy-MM-dd");Date date = sdf.parse("2016/09/10");Calendar cal = Calendar.getInstance();cal.setTime(date);cal.add(Calendar.DAY_OF_MONTH, 10);Date tenDaysLater = cal.getTime();System.out.println(sdf2.format(tenDaysLater));

Java 8中引入了 LocalDateLocalTimeLocalDateTime 分別表示日期、時間、日期和時間,簡單直接,而且就地提供了安全執行緒的日期時間操作,總體來說比7要方便很多了。上面的代碼,在8裡可以這樣寫:

LocalDate today = LocalDate.now();System.out.println("today is " + today);LocalDate specifiedDay = LocalDate.of(2016, Month.JUNE, 1);System.out.println("specific date is " + specifiedDay);LocalDate fifthIn2016 = LocalDate.ofYearDay(2016, 5);System.out.println("5th day of 2016 is " + fifthIn2016);// 預設使用 DateTimeFormatter.ISO_LOCAL_DATELocalDate parsedDay = LocalDate.parse("2016-08-31"); System.out.println("parsed day is " + parsedDay);// 內建 yyyyMMddDateTimeFormatter basicIsoDate = DateTimeFormatter.BASIC_ISO_DATE; // 內建 yyyy-MM-ddDateTimeFormatter isoLocalDate = DateTimeFormatter.ISO_LOCAL_DATE; // 自訂 yyyy:MM:ddDateTimeFormatter customDate = DateTimeFormatter.ofPattern("yyyy:MM:dd"); // 轉換LocalDate formattedDay = LocalDate.parse("20160821", basicIsoDate);System.out.println("isoLocalDate day is " + formattedDay.format(isoLocalDate));System.out.println("customDate day is " + formattedDay.format(customDate));// 時間操作LocalTime now = LocalTime.now();LocalTime later = now.plus(5, HOURS);// 日期操作LocalDate today = LocalDate.now();LocalDate thirtyDaysLater = today.plusDays(30);LocalDate afterOneMonth = today.plusMonths(1);LocalDate beforeOneMonth = today.minusMonths(1);

相對於Calendar操作來說,LocalDate每次都返回一個全新的對象(LocalDate/LocalTime都是final class),這樣做在多線程環境下更安全。

5. 總結

Java 8從應用升級到全面使用,大概還有比較長的路要走,畢竟很多已有的代碼不會為了嘗試新文法和特性而進行更新。在新的工程和代碼中,嘗試新的文法和特性,會帶來更好的體驗和效率。另外,功能等價的代碼,除了文法上的不同,Java 7和Java 8在效能上有什麼不同麼,Java 8真的減少了資源提高了效率嗎?這個問題還得在今後的使用中進一步探討。

6. 參考資料

Joda-Time 
Java 8 新特性
Java 8 基礎實踐

Java 8 不止是Lambdas和Streams

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.