博客 / 詳情

返回

Java8(JDK1.8)新特性

一、Java8(JDK1.8)新特性

1、Lamdba表達式

2、函數式接口

3、方法引用和構造引用

4、Stream API

5、接口中的默認方法和靜態方法

6、新時間日期API

7、OPtional

8、其他特性
二、java8(JDK1.8)新特性簡介

1、速度快;

2、代碼少、簡介(新增特性:lamdba表達式);

3、強大的Stream API;

4、使用並行流和串行流;

5、最大化較少空指針異常Optional;

其中最為核心的是 Lambda表達式和Stream API
三、java8(JDK1.8)新特性詳細介紹
一、Lambda表達式
1、Lambda表達式是什麼?

Lambda是一個匿名函數,我們可以將Lambda表達式理解為一段可以傳遞的代碼(將代碼像數據一樣傳遞)。使用它可以寫出簡潔、靈活的代碼。作為一種更緊湊的代碼風格,使java語言表達能力得到提升。
2、從匿名類到Lambda轉換

package com.chen.test.JAVA8Features;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo01 {
    private static Logger log = LoggerFactory.getLogger(Demo01.class);

    public static void main(String[] args) {
        Runnable t1 =new Runnable(){
            @Override
            public void run(){
                log.info("我是沒有使用Lambda表達式:不簡潔");
            }
        };
        
        Runnable t2 = () -> log.info("我是使用Lambda表達式:簡潔、靈活");
        
        t1.run();
        t2.run();
        
    }
}

Run result

19:43:39.303 [main] INFO com.chen.test.JAVA8Features.Demo01 - 我是沒有使用Lambda表達式:不簡潔、代碼多
19:43:39.303 [main] INFO com.chen.test.JAVA8Features.Demo01 - 我是使用Lambda表達式:簡潔、靈活

Process finished with exit code 0

3、Lambda表達式語法

Lambda表達式在java語言中引入了一種新的語法元素和操作。這種操作符號為“->”,Lambda操作符或箭頭操作符,它將Lambda表達式分割為兩部分。 左邊:指Lambda表達式的所有參數 右邊:指Lambda體,即表示Lambda表達式需要執行的功能。

六種語法格式:

1、語法格式一:無參數、無返回值,只需要一個Lambda體

package com.chen.test.JAVA8Features;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo02 {
    private static Logger log = LoggerFactory.getLogger(Demo02.class);

    public static void main(String[] args) {
        Runnable t1 = ()-> log.info("Lambda表達式:簡潔、靈活,優雅永不過時");
        t1.run();
    }
}
run result
22:22:39.125 [main] INFO com.chen.test.JAVA8Features.Demo02 - Lambda表達式:簡潔、靈活,優雅永不過時

Process finished with exit code 0

2、語法格式二:lambda有一個參數、無返回值

package com.chen.test.JAVA8Features;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.function.Consumer;

public class Demo03 {
    private static Logger log = LoggerFactory.getLogger(Demo03.class);
    public static void main(String[] args) {
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                log.info(s);
            }
        };
        consumer.accept("愛與被愛的區別");

        Consumer<String> consumer1 = (s) -> log.info(s);
        consumer1.accept("接受愛不一定愛對方,愛一定付出真心愛");
    }
}

run result

23:03:08.992 [main] INFO com.chen.test.JAVA8Features.Demo03 - 愛與被愛的區別
23:03:09.142 [main] INFO com.chen.test.JAVA8Features.Demo03 - 接受愛不一定愛對方,愛一定付出真心愛

Process finished with exit code 0

3、語法格式三:Lambda只有一個參數時,可以省略()

package com.chen.test.JAVA8Features;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.function.Consumer;

public class Demo04 {
    private static Logger log = LoggerFactory.getLogger(Demo04.class);
    public static void main(String[] args) {
        Consumer<String> consumer = s -> log.info(s);
        consumer.accept("Lambda只有一個參數時,可以省略()");
    }
}

run result

23:08:27.295 [main] INFO com.chen.test.JAVA8Features.Demo04 - Lambda只有一個參數時,可以省略()

Process finished with exit code 0

4、語法格式四:Lambda有兩個參數時,並且有返回值

package com.chen.test.JAVA8Features;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Comparator;


public class Demo05 {
    private static Logger log = LoggerFactory.getLogger(Demo05.class);

    public static void main(String[] args) {
        CompareOldMethod(12,10);
        findMaxValue(12,10);
        findMinValue(12,10);
    }
//    沒有使用Lambda表達式比較大小
    public static void CompareOldMethod(int num1,int num2){
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                log.info("o1:{}",o1);
                log.info("o2:{}",o2);
                return o1 < o2 ? o2 : o1;
            }
        };
        log.info("OldFindMaxValue:{}",comparator.compare(num1,num2));
    }

//    使用lambda表達式
    public static void findMaxValue(int num1,int num2){
        Comparator<Integer> comparatorMax = (o1, o2) ->{

            log.info("o1:{}",o1);
            log.info("o2:{}",o2);
            return (o1<o2)? o2 :(o1);
        };

        log.info("findMaxValue:{}",(comparatorMax.compare(num1,num2)));

    }
    public static void findMinValue(int num1,int num2){
        Comparator<Integer> comparatorMin =  (o1, o2) -> {
            log.info("o1:{}",o1);
            log.info("o2:{}",o2);
            return (o1 < o2) ? o1 : o2;
        };
        log.info("FindMinValue:{}",comparatorMin.compare(num1,num2));
    }
}

run result

00:17:10.206 [main] INFO com.chen.test.JAVA8Features.Demo05 - o1:12
00:17:10.206 [main] INFO com.chen.test.JAVA8Features.Demo05 - o2:10
00:17:10.206 [main] INFO com.chen.test.JAVA8Features.Demo05 - OldFindMaxValue:12
00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - o1:12
00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - o2:10
00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - findMaxValue:12
00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - o1:12
00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - o2:10
00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - FindMinValue:10

Process finished with exit code 0

5、語法格式五:當Lambda體只有一條語句的時候,return和{}可以省略掉

package com.chen.test.JAVA8Features;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Comparator;


public class Demo05 {
    private static Logger log = LoggerFactory.getLogger(Demo05.class);

    public static void main(String[] args) {
        findMaxValue(12,10);
        findMinValue(12,10);
    }

//    使用lambda表達式
    public static void findMaxValue(int num1,int num2){
        Comparator<Integer> comparatorMax = (o1, o2) ->{

            log.info("o1:{}",o1);
            log.info("o2:{}",o2);
            return (o1<o2)? o2 :(o1);
        };

        log.info("findMaxValue:{}",(comparatorMax.compare(num1,num2)));

    }
    public static void findMinValue(int num1,int num2){
        Comparator<Integer> comparatorMin =  (o1, o2) -> (o1 < o2) ? o1 : o2;

        log.info("FindMinValue:{}",comparatorMin.compare(num1,num2));
    }
}

run result

00:22:31.059 [main] INFO com.chen.test.JAVA8Features.Demo05 - o1:12
00:22:31.075 [main] INFO com.chen.test.JAVA8Features.Demo05 - o2:10
00:22:31.075 [main] INFO com.chen.test.JAVA8Features.Demo05 - findMaxValue:12
00:22:31.075 [main] INFO com.chen.test.JAVA8Features.Demo05 - FindMinValue:10

Process finished with exit code 0

6、語法格式六:類型推斷:數據類型可以省略,因為編譯器可以推斷得出,成為“類型推斷”

package com.chen.test.JAVA8Features;

import com.mysql.cj.callback.MysqlCallbackHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;


public class Demo07 {
    private static Logger log = LoggerFactory.getLogger(Demo07.class);

    public static void main(String[] args) {
        dateType();
    }

    public static void dateType(){
        Consumer<String> consumer = (String s) -> log.info(s);
        consumer.accept("Hello World !");

        Consumer<String> consumer1 = (s) -> log.info(s);
        consumer1.accept("Hello don't date type !");
    }
}

二、函數式接口
1、什麼是函數式接口?

函數式接口:只包含一個抽象方法的接口,稱為函數式接口,並且可以使用lambda表達式來創建該接口的對象,可以在任意函數式接口上使用@FunctionalInterface註解,來檢測它是否是符合函數式接口。同時javac也會包含一條聲明,説明這個接口是否符合函數式接口。
2、自定義函數式接口

package com.chen.test.JAVA8Features;

@FunctionalInterface
public interface FunctionDemo1 {
    public void fun();
}

3、泛型函數式接口

package com.chen.test.JAVA8Features;

@FunctionalInterface
public interface FunctionGeneric<T> {
    public void fun(T t);

}

4、java內置函數式接口

(Function、Consumer、Supplier、Predicate) java.util.function

Function (函數型接口)

函數型接口:有輸入參數,也有返回值。

* @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

其中T表示輸入參數,R為返回值

代碼展示:

   public void functionTest(){
//        Function function = new Function<String,String>(){
//            @Override
//            public String apply(String s) {
//                return s;
//            }
//        };
//        log.info("函數型接口 :{}",function.apply("沒有使用Lambda表達式"));

        Function function = s -> s;
        log.info("函數型接口:{}",function.apply("Function Demo"));
    }

Consumer(消費型接口)

消費型接口:有入參,沒有會有返回值

* @param <T> the type of the input to the operation
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

代碼展示:

 public void consumerTest(){
//        非Lambda表達式
//        Consumer<String> consumer = new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                log.info(s);
//            }
//        };
//        consumer.accept("消費型函數:沒有使用Lambda表達式");

//        使用Lambda表達式
        Consumer<String> consumer = s -> log.info(s);
        consumer.accept("消費型函數:Consumer Demo");

    }

Supplier(供給型接口)

供給型接口:沒有輸入參數,有返回值

*
 * @param <T> the type of results supplied by this supplier
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

代碼展示:

 public void supplierTest(){
//        非Lambda表達式
//        Supplier supplier = new Supplier<String>(){
//            @Override
//            public String get() {
//                return "供給型接口:沒有使用Lambda表達式";
//            }
//        };
//        log.info(String.valueOf(supplier.get()));

        Supplier supplier =  () -> "供給型接口:Supplier Demo";
        log.info(String.valueOf(supplier.get()));
    }

Predicate(斷定型接口)

斷言型接口:既有輸入參數也有返回值,返回類型是boolean類型

* @param <T> the type of the input to the predicate
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

展示代碼:

public void predicateTest() {
//        Predicate<String> predicate = new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                return s.equals("Predicate Demo");
//            }
//        };
//        log.info("斷言型接口:{}",predicate.test("沒有使用Lambda表達式"));
        Predicate<String> predicate = s -> s.equals("Predicate Demo");
        log.info("斷言型接口:{}",predicate.test("Predicate Demo"));
    }

java內置四種大函數式接口,可以使用Lambda表達式

package com.chen.test.JAVA8Features;

import com.google.common.base.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class FunDemo01 {
    private static Logger log = LoggerFactory.getLogger(FunDemo01.class);
    public static void main(String[] args) {
        FunDemo01 demo01 = new FunDemo01();
        demo01.functionTest();
        demo01.consumerTest();
        demo01.supplierTest();
        demo01.predicateTest();

    }
    public void functionTest(){
//        非Lambda表達式
//        Function function = new Function<String,String>(){
//            @Override
//            public String apply(String s) {
//                return s;
//            }
//        };
//        log.info("函數型接口 :{}",function.apply("沒有使用Lambda表達式"));

        Function function = s -> s;
        log.info("函數型接口:{}",function.apply("Function Demo"));
    }

    public void consumerTest(){
//        非Lambda表達式
//        Consumer<String> consumer = new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                log.info(s);
//            }
//        };
//        consumer.accept("消費型函數:沒有使用Lambda表達式");

//        使用Lambda表達式
        Consumer<String> consumer = s -> log.info(s);
        consumer.accept("消費型函數:Consumer Demo");

    }
    public void supplierTest(){
//        非Lambda表達式
//        Supplier supplier = new Supplier<String>(){
//            @Override
//            public String get() {
//                return "供給型接口:沒有使用Lambda表達式";
//            }
//        };
//        log.info(String.valueOf(supplier.get()));

        Supplier supplier =  () -> "供給型接口:Supplier Demo";
        log.info(String.valueOf(supplier.get()));
    }
    public void predicateTest() {
//        Predicate<String> predicate = new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                return s.equals("Predicate Demo");
//            }
//        };
//        log.info("斷言型接口:{}",predicate.test("沒有使用Lambda表達式"));
        Predicate<String> predicate = s -> s.equals("Predicate Demo");
        log.info("斷言型接口:{}",predicate.test("Predicate Demo"));
    }

}

三、方法引用和構造器引用

1、方法引用

當要傳遞給Lambda體的操作已經有實現方法,可以直接使用方法引用(實現抽象方法的列表,必須要和方法引用的方法參數列表一致)

方法引用:使用操作符“::”將方法名和(類或者對象)分割開來。

有下列三種情況:

對象::實例方法

類::實例方法
類::靜態方法

代碼展示:

package com.chen.test.JAVA8Features;

public class MethodRefDemo {
    public static void main(String[] args) {
        FunctionGeneric<String> strName = s -> System.out.println(s);
        strName.fun("Lambda表達式沒有使用方法引用");
        
        //方法引用
        FunctionGeneric<String> strName2 = System.out::println;
        strName2.fun("使用方法引用");


    }
}

2、構造器引用

本質上:構造器引用和方法引用相識,只是使用了一個new方法

使用説明:函數式接口參數列表和構造器參數列表要一致,該接口返回值類型也是構造器返回值類型

格式:ClassName :: new

代碼展示:

package com.chen.test.JAVA8Features;

import java.util.function.Function;

public class MethodRefDemo {
    public static void main(String[] args) {

        //構造器引用
        Function<String, Integer> fun1 = (num) -> new Integer(num);
        Function<String, Integer> fun2 = Integer::new;

        //數組引用
        Function<Integer,Integer[]> fun3 = (num) ->new Integer[num];
        Function<Integer,Integer[]> fun4 = Integer[]::new;
    }
}

四、強大的Stream API
1、什麼是Stream?

Java8中兩個最為重要特性:第一個的是Lambda表達式,另一個是Stream API。

StreamAPI它位於 java.util.stream 包中,StreamAPI幫助我們更好地對數據進行集合操作,它本質就是對數據的操作進行流水線式處理,也可以理解為一個更加高級的迭代器,主要作用是遍歷其中每一個元素。簡而言之,StreamAP提供了一種高效且易於使用的處理數據方式。
2、Stream特點:

1、Stream自己不會存儲數據。

2、Stream不會改變源對象。相反,它們會返回一個持有結果的新Stream對象
3、Stream操作時延遲執行的。這就意味着它們等到有結果時候才會執行。

和list不同,Stream代表的是任意Java對象的序列,且stream輸出的元素可能並沒有預先存儲在內存中,而是實時計算出來的。它可以“存儲”有限個或無限個元素。

例如:我們想表示一個全體自然數的集合,使用list是不可能寫出來的,因為自然數是無線的,不管內存多大也沒法放到list中,但是使用Sream就可以

3、Stream操作的三個步驟?

1、創建Stream:一個數據源(例如:set 、list),獲取一個流

2、中間操作:一箇中間操作連接,對數據源的數據進行處理

3、終止操作:一個終止操作,執行中間操作連,產生結果。

1、創建流

創建流方式有多種:
第一種:通過集合

對於Collection接口(List 、Set、Queue等)直接調用Stream()方法可以獲取Stream

List<String> list = new ArrayList<>();
Stream<String> stringStream = list.stream(); //返回一個順序流
Stream<String> parallelStream = list.parallelStream(); //返回一個並行流(可多線程)

第二種:通過數組

把數組變成Stream使用Arrays.stream()方法

Stream<String> stream1 = Arrays.stream(new String[]{"CBB", "YJJ", "CB", "CJJ"});

第三種:Stream.of()靜態方法直接手動生成一個Stream

Stream<String> stream = Stream.of("A", "B", "C", "D");

第四種:創建無限流

       //迭代
        //遍歷10個奇數
        Stream.iterate(1,t->t+2).limit(10).forEach(System.out::println);

        //生成
        //生成10個隨機數
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
<strong>第五種:自己構建</strong>

第六種:其他等等

2、中間操作

一個流可以後面跟隨着0個或者多箇中間操作,其目的是打開流,做出某種程度的數據過濾、去重、排序、映射、跳過等。然後返回一個新的流,交給下一個使用,僅僅是調用這個方法,沒有真正開始遍歷。

map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

3、終止操作:一個終止操作,執行中間操作連,產生結果。

forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

package com.chen.test.JAVA8Features.Stream;

import java.util.*;
import java.util.stream.Collectors;

public class StreamDemo01 {
    public static void main(String[] args) {

        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);
        }
        //map
        List<Integer> collect = list.stream().map(n -> n * 2).collect(Collectors.toCollection(ArrayList::new));
        collect.forEach(System.out::println);
        //filer 過濾
        List<Integer> list1 = list.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
        list1.forEach(System.out::println);
        //distinct 去重
        List<Integer> list2 = list.stream().distinct().collect(Collectors.toList());
        list2.forEach(System.out::println);
        //skip 跳過
        List<Integer> list3 = list.stream().skip(3).collect(Collectors.toList());
        list3.forEach(System.out::println);
        //limit 截取
        Set<Integer> set = list.stream().limit(3).collect(Collectors.toSet());
        set.forEach(System.out::println);
        //skip  and limit 組合使用
        List<Integer> list4 = list.stream().skip(3).limit(5).collect(Collectors.toList());
        list4.forEach(System.out::println);

    }
}

五、接口中默認方法和靜態方法
1、默認方法

java8允許接口中包含具體實現的方法體,該方法是默認方法,它需要使用default關鍵字修飾
2、靜態方法

java8中允許接口中定義靜態方法,使用static關鍵字修飾

代碼展示:

package com.chen.test.JAVA8Features.DefaultMethod;

public interface DefaultMethodDemo {
    
    default Integer addMethod(int a ,int b){
        System.out.println("我是默認方法");
        return a+b;
    }
    static void test(){
        System.out.println("我是靜態方法");
    }
}

六、新時間日期接口
七、Optional類

optional類是一個容器,代表一個值存在或者不存在,原來使用null表示一個值存不存在,現在使用optional可以更好的表達這個概念,並且可以避免空指針異常。

Optional常用的方法:

Optional.of(T t) : 創建一個Optional實例;

Optional.empty() : 創建一個空的Optional實例;

Optional.ofNullable(T t) :若t不為空創建一個Optional實例否則創建一個空實例;

isPresent() : 判斷是否包含值;

orElse(T t) :如果調用對象包含值,返回該值,否則返回t;

orElseGet(Supplier s) : 如果調用對象包含值,返回該值,否則返回s獲取的值;

map(Function f) : 如果有值對其處理,並返回處理後的Optional,否則返回Optional.empty();

flatMap(Function mapper) : 與map類似,要求返回值必須是Optional。

八、其他等等

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.