Java8特性

java8特性

Oracle 公司於 2014 年 3 月 18 日發佈 Java 8 ,它支持函數式編程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。java

1.lambda表達式 & 函數式接口

詳見lambda表達式總結sql

2. 方法引用

方法引用的規定,實現抽象方法的參數列表,必須與方法引用方法的參數列表保持一致!至於返回值就不做要求數據庫

方法引用經過方法的名字來指向一個方法。方法引用可使語言的構造更緊湊簡潔,減小冗餘代碼。方法引用使用一對冒號 ::編程

引用對象的實例方法 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);
}

總結:指向任意類型實例方法的方法引用有兩個要求:函數式編程

  • 第一點:接口方法的參數比引用方法的參數多一個
  • 第二點:接口方法的第一個參數恰巧是調用引用方法的對象(其引用方法所在類或其父類的實例)

3. 默認方法

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-

4. Stream類

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

  • foreach:迭代流中的每一個數據
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

注:在stream的foreach中,沒法使用break和continue終止循環。使用return;能夠退出本次循環,不影響下一次循環

  • map:用於映射每一個元素到對應的結果
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());
  • filter:經過設置的條件過濾元素
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取空字符串的數量
int count = strings.stream().filter(string -> string.isEmpty()).count();
  • limit:會用獲取指定數量的流
//打印10條數據
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
  • sorted:用於對流進行排序
//10個隨機數排序
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
  • parallel並行程序:parallelStream是流並行處理程序的代替方法
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取空字符串的數量
int count = strings.parallelStream().filter(string -> string.isEmpty()).count();
  • Collectors:規約操做,例如將流轉換爲集合和聚合元素
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);

流搜索

  • findAny:查找任何一個就返回 Optional
  • findFirst:查找到第一個就返回 Optional
  • anyMatch:匹配上任何一個則返回 Boolean
  • allMatch:匹配全部的元素則返回 Boolean
// 查找某一個枚舉值
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));
}

5.Optional類

Optional 類是一個能夠爲null的容器對象。若是值存在則isPresent()方法會返回true,調用get()方法會返回該對象。

Optional 是個容器:它能夠保存類型T的值,或者僅僅保存null。Optional提供不少有用的方法,這樣咱們就不用顯式進行空值檢測。

Optional 類的引入很好的解決空指針異常。

方法 描述
static Optional empty() 返回空的 Optional 實例
boolean equals(Object obj) 判斷其餘對象是否等於 Optional
Optional filter(Predicate<? super predicate) 若是值存在,而且這個值匹配給定的 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 Optional of(T value) 返回一個指定非null值的Optional
static Optional ofNullable(T value) 若是爲非空,返回 Optional 描述的指定值,不然返回空的 Optional
T orElse(T other) 若是存在該值,返回值, 不然返回 other
T orElseGet(Supplier<? extends T> other) 若是存在該值,返回值, 不然觸發 other,並返回 other 調用的結果
T orElseThrow(Supplier<? extends X> exceptionSupplier) 若是存在該值,返回包含的值,不然拋出由 Supplier 繼承的異常
String toString() 返回一個Optional的非空字符串,用來調試
  1. of() 和 ofNullable() 方法
    建立包含值的 Optional。
    兩個方法的不一樣之處在於,若是你把 null 值做爲參數傳遞進去,of() 方法會拋出 NullPointerException。
    明確對象不爲 null 的時候使用 of()。
    若是對象便可能是 null 也多是非 null,你就應該使用 ofNullable() 方法。
    Optional<User> opt = Optional.ofNullable(user);

  2. 返回對象值
  • get():從 Optional 實例中取回實際值對象的方法之一是使用 get() 方法,但若是值是null會拋異常,用以前要判斷,isPresent()
  • orElse():若是有值則返回該值,不然返回傳遞給它的參數值.
//若是user對象爲空,返回user2對象
User result = Optional.ofNullable(user).orElse(user2)
  • orElseGet():有值的時候返回值,若是沒有值,它會執行做爲參數傳入的 Supplier(供應者) 函數式接口
  • 注意:orElse() 和 orElseGet() 的不一樣之處:當對象爲空時無差別。當對象不爲空時,orElse中的方法仍然會執行。
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);
}

6.時間日期API

舊版問題:

  • 非線程安全: java.util.Date 是非線程安全的,全部的日期類都是可變的,這是Java日期類最大的問題之一。
  • 設計不好 − Java的日期/時間類的定義並不一致,在java.util和java.sql的包中都有日期類
  • 時區處理麻煩 − 日期類並不提供國際化,沒有時區支持

Java 8 在 java.time 包下提供了不少新的 API。如下爲兩個比較重要的 API:

  • Local(本地) − 簡化了日期時間的處理,沒有時區的問題。
  • Zoned(時區) − 經過制定的時區處理日期時間。

6.1 LocalDateTime

經常使用方法 描述
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);

7. Base64

Java 8 內置了 Base64 編碼的編碼器和解碼器。
Base64工具類提供了一套靜態方法獲取下面三種BASE64編解碼器:

  • 基本:輸出被映射到一組字符A-Za-z0-9+/,編碼不添加任何行標,輸出的解碼僅支持A-Za-z0-9+/。
  • URL:輸出映射到一組字符A-Za-z0-9+_,輸出是URL和文件。
  • MIME:輸出隱射到MIME友好格式。輸出每行不超過76字符,而且使用'\r'並跟隨'\n'做爲分割。編碼輸出最後沒有行分割

加密解密

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);
相關文章
相關標籤/搜索