一、簡介
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; } }
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"; } }

private static class DefaultableImpl implements Defaulable { }

private static class OverridableImpl implements Defaulable { @Override public String notRequired() { return "Overridden implementation"; } }
Defaulable 接口使用關鍵字 default 定義了一個默認方法 notRequired()。DefaultableImpl 類實現了這個接口,同時默認繼承了這個接口中的默認方法;OverridableImpl 類也實現了這個接口,但覆寫了該接口的默認方法,並提供了一個不同的實現。
Java 8帶來的另一個有趣的特性是在接口中可以定義靜態方法,例子代碼如下:

private interface DefaulableFactory { // Interfaces now allow static methods static Defaulable create( Supplier< Defaulable > supplier ) { return supplier.get(); } }
下面的代碼片段整合了默認方法和靜態方法的使用場景:
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中間操作
- 過濾::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; } }

@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); } }
生成 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); } }); } }
生成 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; } }
以下為測試代碼:

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); } } }

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); } }

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); }); } }

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); }); } }
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。