Oracle 公司於 2014 年 3 月 18 日發佈 Java 8 ,它支持函數式編程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。java
詳見lambda表達式總結sql
方法引用的規定,實現抽象方法的參數列表,必須與方法引用方法的參數列表保持一致!至於返回值就不做要求數據庫
方法引用經過方法的名字來指向一個方法。方法引用可使語言的構造更緊湊簡潔,減小冗餘代碼。方法引用使用一對冒號 ::編程
引用對象的實例方法 | Object::instanceMethodName |
---|---|
引用類的靜態方法 | ClassName::staticMethodName |
引用類的實例方法 | ClassName::methodName |
引用構造方法 | ClassName::new |
一、二、4相對好理解,第三個在Java 8 In Action 是這樣介紹的, 指向任意類型實例方法的方法引用(我以爲叫類的任意對象的實例方法引用更直觀)api
它要求接口方法的參數必須比引用方法的參數多一個。並且第一個參數要是該引用方法的所在類型的或其父類,除接口方法的第一個參數之外, 其他參數的類型要求同樣。安全
example1,一個參數app
public class Test1 { public void a(){ } public static void main(String[] args) { MyInter m = Test1::a; } } @FunctionalInterface interface MyInter { //入參參數比Test1的a方法多一個,且Test1::a的Test1與該入參類型Test1相同 public void d(Test1 d); }
example2,兩個參數dom
public class Test1 { public void a(Integer param1,int param2){ } public static void main(String[] args) { MyInter m = Test1::a; } } @FunctionalInterface interface MyInter { //該接口參數比上述的a方法參數數量多一個,除去第一個,其它類型一致(可兼容,如能夠一個int,一個Integer) //且Test1::a的Test1是該入參類型Test1相同 public void d(Test1 d,int param1,int param2); }
example3 繼承(參考上轉型)ide
public class Test1 { public void a(Integer param1,int param2){ } public static void main(String[] args) { MyInter m = Test1::a; } } class Test2 extends Test1 { } @FunctionalInterface interface MyInter { //該接口參數比上述的a方法參數數量多一個,除去第一個,其它類型一致(可兼容,如能夠一個int,一個Integer) //且Test1::a的Test1是該入參類型Test2的子類(不可顛倒) //個人理解:最後執行的是Test1的a方法,是由入參Test2執行,Test2是子類,確定能夠執行父類的方法,因此ok public void d(Test2 d,int param1,int param2); }
總結:指向任意類型實例方法的方法引用有兩個要求:函數式編程
Java 8 新增了接口的默認方法。咱們只需在方法名前面加個 default 關鍵字便可實現默認方法。
簡單說,默認方法就是接口能夠有實現方法,並且不須要實現類去實現其方法。
Java 8 的另外一個特性是接口能夠聲明(而且能夠提供實現)靜態方法
public class Car { public static void main(String[] args) { A a = new B(); a.print(); } } interface A{ default void print(){ System.out.println("-a-"); } static void staticMethod(){ System.out.println("-do-"); } } class B implements A{ @Override public void print() { A.super.print(); A.staticMethod(); System.out.println("-b-"); } }
運行結果爲
-a-
-do-
-b-
Stream 使用一種相似用 SQL 語句從數據庫查詢數據的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。
Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
注:在stream的foreach中,沒法使用break和continue終止循環。使用return;能夠退出本次循環,不影響下一次循環
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); // 獲取對應的平方數 List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 獲取空字符串的數量 int count = strings.stream().filter(string -> string.isEmpty()).count();
//打印10條數據 Random random = new Random(); random.ints().limit(10).forEach(System.out::println);
//10個隨機數排序 Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println);
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); // 獲取空字符串的數量 int count = strings.parallelStream().filter(string -> string.isEmpty()).count();
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl"); List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList()); System.out.println("篩選列表: " + filtered); String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("合併字符串: " + mergedString);
// 查找某一個枚舉值 public static SwitchEnum findAny(int type) { return Arrays.stream(SwitchEnum.values()) .filter(switchEnum -> switchEnum.getType() == type) .findAny() .orElse(null); } // 匹配到第一個枚舉值就返回 public static SwitchEnum findFirst(String name) { return Arrays.stream(SwitchEnum.values()) .filter(switchEnum -> switchEnum.getName().equals(name)) .findFirst() .orElse(null); } // 枚舉匹配 public static boolean anyMatch(int type) { return Arrays.stream(SwitchEnum.values()) //匹配任何一個則返回 .anyMatch(switchEnum -> switchEnum.getType() == type); } // 枚舉匹配 public static boolean allMatch(String name) { return Arrays.stream(SwitchEnum.values()) //匹配全部 .allMatch(switchEnum -> switchEnum.getName().equals(name)); }
Optional 類是一個能夠爲null的容器對象。若是值存在則isPresent()方法會返回true,調用get()方法會返回該對象。
Optional 是個容器:它能夠保存類型T的值,或者僅僅保存null。Optional提供不少有用的方法,這樣咱們就不用顯式進行空值檢測。
Optional 類的引入很好的解決空指針異常。
方法 | 描述 |
---|---|
static
|
返回空的 Optional 實例 |
boolean equals(Object obj) | 判斷其餘對象是否等於 Optional |
Optional
|
若是值存在,而且這個值匹配給定的 predicate,返回一個Optional用以描述這個值,不然返回一個空的Optional |
Optional flatMap(Function<? super T,Optional> mapper) | 若是值存在,返回基於Optional包含的映射方法的值,不然返回一個空的Optional |
T get() | 若是在這個Optional中包含這個值,返回值,不然拋出異常:NoSuchElementException |
int hashCode() | 返回存在值的哈希碼,若是值不存在 返回 0 |
void ifPresent(Consumer<? super T> consumer) | 若是值存在則使用該值調用 consumer , 不然不作任何事情 |
boolean isPresent() | 若是值存在則方法會返回true,不然返回 false |
Optional map(Function<? super T,? extends U> mapper) | 若是有值,則對其執行調用映射函數獲得返回值。若是返回值不爲 null,則建立包含映射返回值的Optional做爲map方法返回值,不然返回空Optional |
static
|
返回一個指定非null值的Optional |
static
|
若是爲非空,返回 Optional 描述的指定值,不然返回空的 Optional |
T orElse(T other) | 若是存在該值,返回值, 不然返回 other |
T orElseGet(Supplier<? extends T> other) | 若是存在該值,返回值, 不然觸發 other,並返回 other 調用的結果 |
|
若是存在該值,返回包含的值,不然拋出由 Supplier 繼承的異常 |
String toString() | 返回一個Optional的非空字符串,用來調試 |
of() 和 ofNullable() 方法
建立包含值的 Optional。
兩個方法的不一樣之處在於,若是你把 null 值做爲參數傳遞進去,of() 方法會拋出 NullPointerException。
明確對象不爲 null 的時候使用 of()。
若是對象便可能是 null 也多是非 null,你就應該使用 ofNullable() 方法。
Optional<User> opt = Optional.ofNullable(user);
//若是user對象爲空,返回user2對象 User result = Optional.ofNullable(user).orElse(user2)
User result = Optional.ofNullable(user).orElse(new User("extra@gmail.com", "1234")); User result2 = Optional.ofNullable(user).orElseGet(User::new); //user不爲空,上面的構造方法仍然執行了
取值實例:
//傳統判斷: if (user != null) { AddressEntity addressEntity = user.getAddressEntity(); if (addressEntity != null) { String address = addressEntity.getAddress(); if (address != null && address.length() > 3) { return address; } } } //optional return Optional.ofNullable(user) .map(u -> u.getAddressEntity()) .map(a -> a.getAddress()) .filter(s -> s.length() > 3) .orElse(null);
判斷操做:
public static void doThing(String name) { if (name != null) { System.out.println(name); } } public static void doThingOptional(String name) { Optional.ofNullable(name) .ifPresent(System.out::println); }
舊版問題:
Java 8 在 java.time 包下提供了不少新的 API。如下爲兩個比較重要的 API:
經常使用方法 | 描述 |
---|---|
LocalDateTime.now() | 獲取當前時間 |
of(int ...) | 能夠根據年月日時分,年月日時分秒,年月日時分秒毫秒等 獲取時間 |
parse(CharSequence text) | 根據文本建立時間,形如"2007-12-03T10:15:30" |
toLocalDate() | 獲取當前日期對象 |
toLocalTime() | 獲取當前時間對象 |
getYear() | 年 |
getMonth() | 月(是個對象) |
getMonthValue() | 月值,eg:12 |
getDayOfMonth()、getDayOfYear()、getDayOfWeek() | 當前是月、年、周的第幾天 |
getHour()、getSecond()、getSecond()、getNano() | 獲取時、分、秒、毫秒 |
withYear(int year).. | 替換時間,能夠替換Year、Month、DayOfMonth、DayOfYear、Hour、Minute、Second、Nano |
plusYears(long),plusMonth(long)... | 一天後的時間,一年後的時間。(年,..,毫秒) |
minYears(long),minMonths(long) | 一天前的時間,(年,...,毫秒) |
isAfter(LocalDataTime ldt) | 對比當前對象時間是否在參數對象時間以後?返回boolean |
isBefore(LocalDataTime ldt) | 對比以前 |
isEqual(LocalDataTime ldt) | 對比是否相等 |
實例:
// 獲取當前的日期時間 LocalDateTime currentTime = LocalDateTime.now(); System.out.println("當前時間: " + currentTime); LocalDate date1 = currentTime.toLocalDate(); System.out.println("date1: " + date1); Month month = currentTime.getMonth(); int day = currentTime.getDayOfMonth(); int seconds = currentTime.getSecond(); System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds); LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012); System.out.println("date2: " + date2); // 12 december 2014 LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12); System.out.println("date3: " + date3); // 22 小時 15 分鐘 LocalTime date4 = LocalTime.of(22, 15); System.out.println("date4: " + date4); // 解析字符串 LocalTime date5 = LocalTime.parse("20:15:30"); System.out.println("date5: " + date5);
Java 8 內置了 Base64 編碼的編碼器和解碼器。
Base64工具類提供了一套靜態方法獲取下面三種BASE64編解碼器:
加密解密
String text = "base64 in java8 lib"; //編碼 String encode = Base64.getEncoder() .encodeToString(text.getBytes(StandardCharsets.UTF_8)); System.out.println(encode); //解碼 String decode = new String(Base64.decode(encode), StandardCharsets.UTF_8); System.out.println(decode);