Java學習之==>Java8 新特性詳解


一、簡介

  Java 8 已經發布很久了,很多報道表明Java 8 是一次重大的版本升級。Java 8是 Java 自 Java 5(發布於2004年)之后的最重要的版本。這個版本包含語言、編譯器、庫、工具和JVM等方面的十多個新特性。在本文中我們將學習這些新特性,並用實際的例子說明在什么場景下適合使用。

  • 語言
  • 編譯器
  • 工具
  • JVM

二、Java語言的新特性

1、Lambda表達式

  Lambda 表達式(也稱為閉包)是Java 8中最大和最令人期待的語言改變。它允許我們將函數當成參數傳遞給某個方法,或者把代碼本身當作數據處理,函數式開發者非常熟悉這些概念。

Lambda 表達式的組成:

  • 參數列表部分, 位於表達式左側的括號內
    • (o1,o2)->{}
    • ()->{}
    • x ->{}
  • 語法標識符,或參數與代碼體分隔符
    • ->
  • 代碼塊,代碼體
    • 一般多行代碼使用括號包起來;
    • 如果只有一行代碼,可以省略括號不寫;
    • 有return則需寫return帶有返回值,如果沒有則不寫;
    • (params) -> code-body

舉例:

public void test1(){
  // 原始代碼
  new Thread(new Runnable() {

    @Override
    public void run() {
      System.out.println("I love lambda");
    }
  }).start();

  // 使用lambda之后的效果
  new Thread(() -> System.out.println("I love lambda")).start();
}

Lambda表達式-函數式接口:

  函數接口指的是只有一個函數的接口,這樣的接口可以隱式轉換為Lambda表達式。在實踐中,函數式接口非常脆弱:只要某個開發者在該接口中添加一個函數,則該接口就不再是函數式接口進而導致編譯失敗。為了克服這種代碼層面的脆弱性,並顯式說明某個接口是函數式接口,Java 8 提供了一個特殊的注解@FunctionalInterface(Java 庫中的所有相關接口都已經帶有這個注解了),上面代碼中的 Runnable 就是函數式接口,源碼如下:

自定義函數式接口

/**
 * 自定義函數式接口
 */
@FunctionalInterface
public interface FooIface<R, T, S, U> {

  R foo(T t, S s, U u);

  static void test2() {
  }

  default void test1() {
  }
}

值得注意的是,默認方法和靜態方法不會破壞函數式接口的定義,因此以上的代碼是合法的。

Lambda表達式-四大類函數式接口:

消費型

  • java.util.function.Consumer
public void testConsumer() {
  /**
   * 消費型
   * 有參,無返回值
   */
  Consumer<String> consumer1 = new Consumer<String>() {
     @Override
     public void accept(String s) {
       System.out.println(s);
     }
   };

  Consumer<String> consumer2 = s -> System.out.println(s);
  
}

供給型

  • java.util.function.Supplier
public void testSupplier() {
  /**
   * 供給型
   * 無參,有返回值
   * () -> "hello";
   */
  Supplier<String> supplier1 = new Supplier<String>() {
    @Override
    public String get() {
      return "hello";
    }
  };

  Supplier<String> supplier2 = () -> "hello";
}

斷言型

  • java.util.function.Predicate
public void testPredicate() {
  /**
   * 斷言型
   * 有參數,返回值是boolean類型
   */
  Predicate<String> predicate1 = new Predicate<String>() {

    @Override
    public boolean test(String s) {
      return s.startsWith("abc_");
    }
  };

  Predicate<String> predicate2 = s -> s.startsWith("abc_");

}

轉化型

  • java.util.function.Function
public void testFunction() {
  /**
   * 轉化型
   * 有參數,有返回,但是參數和返回是不同的數據類型
   */
  Function<String, Integer> function1 = new Function<String, Integer>() {

    @Override
    public Integer apply(String s) {
      return s.length();
    }
  };

  Function<String, Integer> function2 = s -> s.length();
  Function<String, Integer> function3 = String::length;
}

2、方法引用

  方法引用使得開發者可以直接引用現存的方法、Java類的構造方法或者實例對象。方法引用和Lambda表達式配合使用,使得java類的構造方法看起來緊湊而簡潔,沒有很多復雜的模板代碼。先來看一下下面這段代碼:

public void test4() {
  /**
   * 方法引用
   interface Comparator<T>
   int compare(T o1, T o2);

   Integer#compare(int x, int y)
   public static int compare(int x, int y) {
   return (x < y) ? -1 : ((x == y) ? 0 : 1);
   }
   */
  // 原始寫法,java8之前
  Comparator<Integer> comparator1 = new Comparator<Integer>() {

    @Override
    public int compare(Integer o1, Integer o2) {
      return Integer.compare(o1, o2);
    }
  };

  // 基於lambda改寫后的,第一種寫法,但是有冗余代碼,比如return和代碼塊的大括號
  Comparator<Integer> comparator2 = (x, y) -> { return Integer.compare(x, y); };

  // 再一次改寫,去掉了return,因為我明明知道就是要return,還需要你再寫嗎?
  Comparator<Integer> comparator3 = (x, y) -> Integer.compare(x, y);

  // 最終,這兩個形參x,y其實只是一個占位而已,接受者Integer::compare就知道有這樣兩個參數傳進來,大家心知肚明的事情, 就省略嘛
  Comparator<Integer> comparator4 = Integer::compare;

  int x = 10;
  int y = 20;

  System.out.println(comparator1.compare(x, y));
  System.out.println(comparator2.compare(x, y));
  System.out.println(comparator3.compare(x, y));
  System.out.println(comparator4.compare(x, y));
}

以上這段代碼寫了從最原始的寫法到使用 Lambda 改寫后的寫法再到最終的方法引用。

方法引用包括四類:

構造方法引用

  • Supplier supplier = String::new;
  • Function<String, String> function = String::new;
  • Function<Integer, List> function = ArrayList::new;
  • BiFunction<Integer, Float, HashMap> biFunction = HashMap::new;
  • Function<Integer, String[]> function = String[]::new;

靜態方法引用

  • class::statisMethod
    • Comparator comparator = Integer::compare;

成員方法引用

  • class::Method
    • BiPredicate<String, String> predicate = String::equals;

示例對象的方法引用

  • class::instanceMethod
    • Supplier supplier = linkedList::pop;

自定義類實現方法引用

public class StringLengthCompare {

  public static int abc(String o1, String o2) {
    return o1.length() > o2.length() ? 1 : -1;
  }

  public int bcd(String o1, String o2) {
    return o1.length() > o2.length() ? 1 : -1;
  }
}
StringLengthCompare 類
public void test5() {
  /**
   * 第一種,原始寫法
   */
  Comparator<String> comparator = new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
      return o1.length() > o2.length() ? 1 : -1;
    }
  };

  int res = comparator.compare("abc", "ab");
  System.out.println(res);
  
  /**
   * 第二種,使用lambda改寫
   */
  Comparator<String> comparator1 = (str1, str2) -> str1.length() > str2.length() ? 1 : -1;

  res = comparator1.compare("abc", "ab");
  System.out.println(res);
  
  /**
   * 第三種,自定義StringLengthCompare類實現方法引用
   */
  // abc為靜態方法,直接用類名調用
  Comparator<String> comparator2 = StringLengthCompare::abc;
  System.out.println("comparator2 = " + comparator2);

  // bcd為非靜態方法,需要用對象來調用
  StringLengthCompare stringLengthCompare = new StringLengthCompare();
  Comparator<String> comparator3 = stringLengthCompare::bcd;
  System.out.println("comparator3 = " + comparator3);
}

3、接口的靜態方法和默認方法

  Java 8 使用兩個新概念擴展了接口的含義:默認方法和靜態方法。默認方法使得開發者可以在不破壞二進制兼容性的前提下,往現存接口中添加新的方法,即不強制那些實現了該接口的類也同時實現這個新加的方法。默認方法和抽象方法之間的區別在於抽象方法需要實現,而默認方法不需要。接口提供的默認方法會被接口的實現類繼承或者覆寫,例子代碼如下:

private interface Defaulable {
    // Interfaces now allow default methods, the implementer may or 
    // may not implement (override) them.
    default String notRequired() { 
        return "Default implementation"; 
    }        
}
Defaulable
private static class DefaultableImpl implements Defaulable {
}
DefaultableImpl
private static class OverridableImpl implements Defaulable {
    @Override
    public String notRequired() {
        return "Overridden implementation";
    }
}
OverridableImpl

Defaulable 接口使用關鍵字 default 定義了一個默認方法 notRequired()。DefaultableImpl 類實現了這個接口,同時默認繼承了這個接口中的默認方法;OverridableImpl 類也實現了這個接口,但覆寫了該接口的默認方法,並提供了一個不同的實現。

Java 8帶來的另一個有趣的特性是在接口中可以定義靜態方法,例子代碼如下:

private interface DefaulableFactory {
    // Interfaces now allow static methods
    static Defaulable create( Supplier< Defaulable > supplier ) {
        return supplier.get();
    }
}
DefaulableFactory

下面的代碼片段整合了默認方法和靜態方法的使用場景:

public static void main( String[] args ) {
    Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
    System.out.println( defaulable.notRequired() );

    defaulable = DefaulableFactory.create( OverridableImpl::new );
    System.out.println( defaulable.notRequired() );
}

這段代碼輸入結果如下:

Default implementation
Overridden implementation

由於JVM上的默認方法的實現在字節碼層面提供了支持,因此效率非常高。默認方法允許在不打破現有繼承體系的基礎上改進接口。該特性在官方庫中的應用是:給java.util.Collection接口添加新方法,如stream()、parallelStream()、forEach() 和removeIf() 等等。盡管默認方法有這么多好處,但在實際開發中應該謹慎使用:在復雜的繼承體系中,默認方法可能引起歧義和編譯錯誤。

注意:實現接口的類或者子接口不會繼承接口中的靜態方法

4、重復注解

在 Java學習之==>注解 這篇文章中有關於重復注解的介紹和使用。重復注解也是在 Java 8 中才開始支持的。

三、Java 官方庫的新特性

1、Streams

新增的 Stream API(java.util.stream)將函數式編程引入了 Java 庫中。這是目前為止最大的一次對 Java 庫的完善,以便開發者能夠寫出更加有效、更加簡潔和緊湊的代碼。Steam API 極大的簡化了集合操作(后面我們會看到不止是集合)。

Stream概述

  • 非主流式定義: 像寫SQL一樣來處理集合;
  • 理解類定義: 流式處理;
  • 流式處理學習路線: 創建,操作(中間操作,終止操作);

Stream創建

  • Collection等集合接口實現的stream()方法和parallelStream()方法;
  • Arrays提供的數組流;
  • Stream類提供的靜態創建方法of();
public class Demo {

  public static void main(String[] args) {
    /**
     * 創建Stream流,有三種方式
     */
    // 第一種,集合類自帶的方法
    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream();

    Set<String> set = null;
    Stream<String> stream1 = set.stream();

    // 第二種,數組類流的創建
    int[] arr = new int[]{1, 2, 3};
    IntStream stream2 = Arrays.stream(arr);

    /**
     * public static<T> Stream<T> of(T... values) {
     *   return Arrays.stream(values);
     *  }
     */
    // 第三種,Stream接口自己提供的of方法,從實現來看是和第二種是一樣的
    Stream<String> stream3 = Stream.of("", "", "");
  }
}
創建Stream流的三種方式

Stream中間操作

  • 過濾::filter;
  • 切片 & 分頁:sklip , limit;
  • 去重:distinct(去重的對象需要實現hashCode和equals);
  • 映射:map, flatMap;
  • 排序:sort;

Stream終止操作

  • 匹配
    • allMatch:檢查是否匹配所有元素;
    • anyMatch:檢查是否匹配至少一個元素;
    • noneMatch:檢查是否沒有匹配所有元素
  • 查找
    • findFirst:查找找到的第一個元素;
    • findAny:查找找到的任意一個元素
  • 計算流中元素個數:count();
  • 計算流中元素的最大/最小值:max() , min();
  • 內部迭代:forEach;
  • 收集:collect;

下面我們來舉例操作一下:

首先定義兩個實體類 Account 和 User 

@Setter
@Getter
@ToString
public class Account {

  private int id;

  private String accountName;

  private boolean isInner;
  private boolean isA;
  private boolean isB;
  private boolean isC;

  private String type;

  private List<User> users;

  private Account() {
  }

  private Account(int id, String accountName, boolean isInner, String type, List<User> users) {
    this.id = id;
    this.accountName = accountName;
    this.isInner = isInner;
    this.type = type;
    this.users = users;
  }

  public Account(int id, String accountName, boolean isInner, boolean isA, boolean isB, boolean isC,
      String type) {
    this.id = id;
    this.accountName = accountName;
    this.isInner = isInner;
    this.isA = isA;
    this.isB = isB;
    this.isC = isC;
    this.type = type;
  }

  public static Account of(int id, String accountName, boolean isInner, String type,
      List<User> users) {
    return new Account(id, accountName, isInner, type, users);
  }

  public static Account of(int id, String accountName, boolean isInner, boolean isA, boolean isB,
      boolean isC,
      String type) {
    return new Account(id, accountName, isInner, isA, isB, isC, type);
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    Account account = (Account) o;

    if (id != account.id) {
      return false;
    }
    return accountName != null ? accountName.equals(account.accountName)
        : account.accountName == null;
  }

  @Override
  public int hashCode() {
    int result = id;
    result = 31 * result + (accountName != null ? accountName.hashCode() : 0);
    return result;
  }
}
Account
@Setter
@Getter
@ToString
public class User {

  private int id;

  private String name;

  private User() {
  }

  private User(int id, String name) {
    this.id = id;
    this.name = name;
  }

  public static User of(int id, String name) {
    return new User(id, name);
  }

  // @Override
  // public boolean equals(Object o) {
  //   if (this == o) {
  //     return true;
  //   }
  //   if (o == null || getClass() != o.getClass()) {
  //     return false;
  //   }
  //   User user = (User) o;
  //   return id == user.id &&
  //       Objects.equal(name, user.name);
  // }
  //
  // @Override
  // public int hashCode() {
  //   return Objects.hashCode(id, name);
  // }


  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    User user = (User) o;
    return id == user.id;
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(id);
  }
}
User

生成 Account 對象集合的類 AccountFactory

public class AccountFactory {

  public static List<Account> getSimpleAccounts() {

    List<Account> accounts = new ArrayList<>();

    accounts.add(Account.of(1, "微信支付1賬戶", false, "出款", UserFactory.getSimpleUsers(true)));
    accounts.add(Account.of(2, "微信支付2賬戶", false, "入款", UserFactory.getSimpleUsers(true)));
    accounts.add(Account.of(3, "微信支付3賬戶", true, "出款", UserFactory.getSimpleUsers(false)));
    accounts.add(Account.of(4, "微信支付4賬戶", true, "入款", UserFactory.getSimpleUsers(true)));
    accounts.add(Account.of(5, "微信支付5賬戶", false, "出款", UserFactory.getSimpleUsers(false)));
    accounts.add(Account.of(6, "微信支付6賬戶", false, "入款", UserFactory.getSimpleUsers(true)));
    accounts.add(Account.of(7, "微信支付7賬戶", false, "出款", UserFactory.getSimpleUsers(false)));
    accounts.add(Account.of(8, "微信支付8賬戶", true, "出款", UserFactory.getSimpleUsers(true)));
    accounts.add(Account.of(9, "微信支付9賬戶", true, "入款", UserFactory.getSimpleUsers(false)));
    accounts.add(Account.of(10, "微信支付10賬戶", true, "出款", UserFactory.getSimpleUsers(true)));
    accounts.add(Account.of(11, "微信支付11賬戶", true, "入款", UserFactory.getSimpleUsers(true)));
    accounts.add(Account.of(12, "微信支付12賬戶", false, "出款", UserFactory.getSimpleUsers(true)));

    return accounts;
  }

  public static List<Account> getSimpleABCAccounts() {

    List<Account> accounts = new ArrayList<>();

    accounts.add(Account.of(1, "微信支付1賬戶", false, false, true, true, "出款"));
    accounts.add(Account.of(2, "微信支付2賬戶", false, false, false, true, "入款"));
    accounts.add(Account.of(3, "微信支付3賬戶", true, false, true, false, "出款"));
    accounts.add(Account.of(4, "微信支付4賬戶", true, false, true, true, "入款"));
    accounts.add(Account.of(5, "微信支付5賬戶", false, false, false, false, "出款"));
    accounts.add(Account.of(6, "微信支付6賬戶", false, false, true, true, "入款"));
    accounts.add(Account.of(7, "微信支付7賬戶", false, false, false, false, "出款"));
    accounts.add(Account.of(8, "微信支付8賬戶", true, false, false, true, "出款"));
    accounts.add(Account.of(9, "微信支付9賬戶", true, false, true, true, "入款"));
    accounts.add(Account.of(10, "微信支付10賬戶", true, false, false, false, "出款"));
    accounts.add(Account.of(11, "微信支付11賬戶", true, false, false, true, "入款"));
    accounts.add(Account.of(12, "微信支付12賬戶", false, false, true, true, "出款"));

    return accounts;
  }

  public static void printAccount(List<Account> accounts) {
    for (Account account : accounts) {
      System.out.println("account = " + account);
    }
  }

  public static void printAccount(Map<String, List<Account>> accounts) {
    accounts.forEach((key, val) -> {
      System.out.println("groupName:" + key);
      for (Account account : val) {
        System.out.println("\t\t account:" + account);
      }
    });
  }
}
AccountFactory

生成 User 對象集合的類 UserFactory

public class UserFactory {

  public static List<User> getSimpleUsers(boolean type) {

    List<User> users = Lists.newArrayList();

    if (type) {
      users.add(User.of(1, "張三"));
      users.add(User.of(1, "李四"));
      users.add(User.of(1, "王五"));
    } else {
      users.add(User.of(1, "張三"));
      users.add(User.of(1, "李四"));
      users.add(User.of(1, "王五"));
      users.add(User.of(1, "王二麻子"));
      users.add(User.of(1, "小淘氣"));
    }

    return users;
  }

  public static List<User> getSimpleUsers() {

    List<User> users = Lists.newArrayList();

    users.add(User.of(1, "張三"));
    users.add(User.of(1, "李四"));
    users.add(User.of(1, "王五"));
    users.add(User.of(1, "王五"));
    users.add(User.of(1, "王五"));
    users.add(User.of(1, "王五"));
    users.add(User.of(1, "王五"));
    users.add(User.of(1, "王二麻子"));
    users.add(User.of(1, "小淘氣"));

    return users;
  }
}
UserFactory

以下為測試代碼:

public class StreamDemo1 {

  /**
   * 過濾:原始寫法
   */
  @Test
  public void test1() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();
    List<Account> accs = new ArrayList<>();
    for (Account account : accounts) {
      if (account.isInner()) {
        accs.add(account);
      }
    }
    AccountFactory.printAccount(accs);
  }

  /**
   * 過濾:java8寫法
   */
  @Test
  public void test2() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();
    List<Account> accs = accounts
        .stream() // 創建流
        .filter(Account::isInner) // 中間操作
        .collect(Collectors.toList()); // 終止操作
    AccountFactory.printAccount(accs);
  }

  /**
   * 分組:原始寫法
   */
  @Test
  public void test3() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    Map<String, List<Account>> group = new HashMap<>();
    for (Account account : accounts) {
      if (group.containsKey(account.getType())) {
        group.get(account.getType()).add(account);
      } else {
        List<Account> acc = new ArrayList<>();
        acc.add(account);
        group.put(account.getType(), acc);
      }
    }
    AccountFactory.printAccount(group);
  }

  /**
   * 分組:java8的寫法
   */
  @Test
  public void test4() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    Map<String, List<Account>> group = accounts
        .stream()
        .collect(Collectors.groupingBy(Account::getType));
    AccountFactory.printAccount(group);
  }

  /**
   * 分組, 對內部賬戶進行分組
   */
  @Test
  public void test5() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    Map<String, List<Account>> group = new HashMap<>();
    for (Account account : accounts) {

      if (!account.isInner()) {
        continue;
      }

      if (account.isA()) {
        continue;
      }

      if (!account.isB()) {
        continue;
      }

      if (group.containsKey(account.getType())) {
        group.get(account.getType()).add(account);
      } else {
        List<Account> acc = new ArrayList<>();
        acc.add(account);
        group.put(account.getType(), acc);
      }
    }
    AccountFactory.printAccount(group);
  }

  /**
   * 基於java8的分組,對內部賬戶進行分組
   */
  @Test
  public void test6() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    Map<String, List<Account>> group = accounts
        .stream()
        .filter(Account::isInner)
        .filter(account -> !account.isB())
        .filter(Account::isC)
        .collect(Collectors.groupingBy(Account::getType));

    AccountFactory.printAccount(group);
  }

  @Test
  public void test7() {

    /**
     * filter是中間操作
     * filter操作完以后Stream對象類型不變
     */
    Stream<String> stream = Stream.of("abc_d", "ef", "abc_123")
        .filter(str -> str.startsWith("abc_"));

    /**
     * collect是終止操作
     * collect操作完以后Stream對象類型變成其他類型了
     */
    List<String> collect = Stream.of("abc_d", "ef", "abc_123")
        .filter(str -> str.startsWith("abc_"))
        .collect(Collectors.toList());

    for (String s : collect) {
      System.out.println(s);
    }
  }
}
StreamDemo1
public class StreamDemo2 {

  /**
   * map:映射,獲取對象的某個屬性
   * 返回所有內部賬戶的賬戶名
   */
  @Test
  public void testMap() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    List<String> list = accounts.stream()
        .filter(Account::isInner)
        .map(Account::getAccountName)
        .collect(Collectors.toList());

    for (String s : list) {
      System.out.println(s);
    }
  }

  /**
   * skip:切片,去除前面幾條
   */
  @Test
  public void testSkip() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    List<Account> list = accounts
            .stream()
            .skip(5)
            .collect(Collectors.toList());
    for (Account account : list) {
      System.out.println(account);
    }
  }

  /**
   * skip:切片,去除調前面幾條
   * limit:分頁,控制結果的數量
   */
  @Test
  public void testLimit() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    List<Account> list = accounts
            .stream()
            .skip(3)
            .limit(5)
            .collect(Collectors.toList());
    for (Account account : list) {
      System.out.println(account);
    }
  }


  /**
   * 拿出account中user列表的名字
   *
   * 去重
   */
  @Test
  public void testflatMap() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    // 這個搞不定
    List<List<String>> res = accounts.stream()
        .map(account -> {
          List<User> users = account.getUsers();
          return users.stream().map(User::getName).collect(Collectors.toList());
        })
        .distinct()
        .collect(Collectors.toList());

    System.out.println("res:" + res);

    List<String> res2 = accounts.stream()
        // [[1,2],[1,2,3],[1,2,3,4]]
        .flatMap(account -> account.getUsers().stream())
        //[1,2,1,2,3,1,2,3,4]
        .map(User::getName)
        .distinct()
        .collect(Collectors.toList());
    System.out.println("res2:" + res2);
  }
}
StreamDemo2
public class StreamDemo3 {

  @Test
  public void testMaxOrMin() {

    List<Account> accounts = AccountFactory.getSimpleAccounts();

    Optional<Integer> optional = accounts.stream()
        .filter(Account::isInner)
        .map(Account::getId)
            /**
             * peek,調試時輸出值
             */
        .peek(System.out::println)
        .max(Integer::compare);

    Integer maxId = optional.get();

    System.out.println("maxId = " + maxId);
  }

  @Test
  public void testForeach() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    accounts.stream()
        .filter(Account::isInner)
        .map(Account::getId)
        .forEach(System.out::println);
  }

  @Test
  public void testFind() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    Optional<Integer> optional = accounts.stream()
        .filter(Account::isInner)
        .map(Account::getId)
        .findAny();

    System.out.println("optional.get() = " + optional.get());
  }

  @Test
  public void testMatch() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();

    boolean match = accounts.stream()
        .anyMatch(Account::isInner);
    System.out.println("match = " + match);
  }

  @Test
  public void testMapForeach() {
    Map<String, String> mapData = Maps.newHashMap();

    mapData.put("hello", "hi");
    mapData.put("yes", "no");

    mapData.forEach((key, val) -> {
      System.out.println(key + "," + val);
    });
  }
}
StreamDemo3
public class StreamDemo4 {

  /**
   * 我以accountName作為key,來划分Account
   *
   * list<account> = [account,account]
   *
   * map<string,account> = {(accountName,account),(accountName,account)} map<string,account.id> =
   * {(accountName,account),(accountName,account)}
   */
  @Test
  public void test1() {
    List<Account> accounts = AccountFactory.getSimpleAccounts();
     Map<String, Account> map = accounts
         .stream()
         .collect(Collectors.toMap(Account::getAccountName, account -> account));

     map.forEach((key, val) -> {
       System.out.println(key + "," + val);
     });
  }

  @Test
  public void test2(){
    List<Account> accounts = AccountFactory.getSimpleAccounts();
    Map<String, Integer> map = accounts
            .stream()
            .collect(Collectors.toMap(Account::getAccountName, Account::getId));

    map.forEach((key, val) -> {
      System.out.println(key + "," + val);
    });
  }
}
StreamDemo4

2、Date/Time API(JSR 310)

 

3、Optional

簡介

  • Optional 類是一個可以為 null 的容器對象。如果值存在則 isPresent() 方法會返回true,調用get()方法會返回該對象。
  • Optional 是個容器:它可以保存類型T的值,或者僅僅保存null。Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測。
  • Optional 類的引入很好的解決空指針異常。

類的屬性和方法

從圖中我們可以看出,它的構造方法都是private修飾的,其實是一個單例模式的應用。

下面我們主要來講一下 filter() 和 map() 方法:

filter 方法

該方法是過濾方法,過濾符合條件的 Optional 對象,這里的條件用 Lambda 表達式來定義,源碼如下:

    public Optional<T> filter(Predicate<? super T> predicate) {
        //如果入參predicate對象為null將拋NullPointerException異常
        Objects.requireNonNull(predicate);
        //如果Optional對象的值為null,將直接返回該Optional對象
        if (!isPresent())
            return this;
        //如果Optional對象的值符合限定條件(Lambda表達式來定義),返回該值,否則返回空的Optional對象
        else
            return predicate.test(value) ? this : empty();
    }

map 方法

map方法用於修改該值,並返回修改后的Optional對象,一般會在多級取值的時候用到,源碼如下:

    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        //如果入參mapper對象為null將拋NullPointerException異常
        Objects.requireNonNull(mapper);
        //如果Optional對象的值為null,將直接返回該Optional對象
        if (!isPresent())
            return empty();
        //執行傳入的lambda表達式,並返回經lambda表達式操作后的Optional對象
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }

舉例:

判斷不為null然后進行操作

public class Demo {
  /**
   * 不為null時進行操作
   * 原始寫法
   */
  public static void doThing(String name) {
    if (name != null) {
      System.out.println(name);
    }
  }

  // 使用Optional的寫法
  public static void doThingOptional(String name) {
    Optional.ofNullable(name).ifPresent(System.out::println);
  }
}

多層級取值

public class Demo {
  
  // 原始寫法
  public static String getAddress(User user) {
    if (user != null) {
      AddressEntity addressEntity = user.getAddressEntity();
      if (addressEntity != null) {
        String address = addressEntity.getAddress();
        if (address != null && address.length() > 3) {
          return address;
        }
      }
    }
    return null;
  }

  // 使用Optional的寫法
  public static String getAddressOptional(User user) {
    return Optional.ofNullable(user)
            .map(u -> u.getAddressEntity())
            .map(a -> a.getAddress())
            .filter(s -> s.length() > 3)
            .orElse(null);
  }
}

四、JVM 的新特性

  使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM參數方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原來的-XX:PermSize和-XX:MaxPermSize。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM