Java8特性

Java8特性

接口定義增強

JDK1.8之前,接口的組成只有全局變量抽象方法。從JDK1.8開始,接口的組成增加了。
假設:現有一個接口,其子類有2W個。現在發現該接口功能不足,要增加一個方法,該方法對於所有子類而言的功能是一樣的(即方法體是一樣的)。此時要修改每個子類的方法,要修改2W次。
上述問題在JDK1.8中不存在,因爲其允許接口中定義普通方法,但普通方法必須使用default定義。

interface Fruit {
    public void print(); // 接口原本定義的方法

    default public void fun() { // 普通方法
        System.out.println("JDK1.8");
    }
}

class Apple implements Fruit {
    @Override
    public void print() {
        System.out.println("蘋果");
    }
}

public class Demo {
    public static void main(String[] args) {
        Fruit f = new Apple();
        f.fun();
        f.print();
    }
}

除了使用default定義方法,還可以使用static定義方法
範例:定義static方法

interface Fruit {
    public void print(); // 接口原本定義的方法

    default public void fun() { // 普通方法
        System.out.println("JDK1.8");
    }

    static void get() {
        System.out.println("直接由接口調用");
    }
}

class Apple implements Fruit {
    @Override
    public void print() {
        System.out.println("蘋果");
    }
}

public class Demo {
    public static void main(String[] args) {
        Fruit f = new Apple();
        f.fun();
        f.print();
        Fruit.get();
    }
}

JDK1.8有個新功能:內部類訪問方法參數時可以不加上final關鍵字。
這些新特性,完全打破了Java已有的代碼組成形式。

Lamda表達式

Lamda屬於函數式編程的概念,下面通過匿名內部類,來分析函數式編程的產生目的。
範例:匿名內部類

interface Fruit {
    public void print(); // 接口原本定義的方法
}


public class Demo {
    public static void main(String[] args) {
        fun(new Fruit() {
            @Override
            public void print() {
                System.out.println("水果");
            }
        });
    }

    public static void fun(Fruit fru) {
        fru.print();
    }
}

上述代碼中fun()最終需要的只是輸出,但是由於Java的開發結構的完整性要求,不得不在這個核心語句上嵌套更多的內容。但是該做法過於嚴謹複雜,在JDK1.8引入函數式編程,簡化過程。
範例:使用Lamda表達式

interface Fruit {
    public void print(); // 接口原本定義的方法
}

public class Demo {
    public static void main(String[] args) {
        fun(()-> System.out.println("水果"));
    }
    public static void fun(Fruit fru) {
        fru.print();
    }
}

Lamda語法有三種形式:

·(參數)->單行語句;
·(參數)->{單行語句};
·(參數)->表達式;

範例:觀察有參單行

interface Fruit {
    public void print(String str); // 接口原本定義的方法
}

public class Demo {
    public static void main(String[] args) {
        // 首先要定義此表達式裏面需要接收變量,單行語句直接進行輸出
        fun((s) -> System.out.println(s));
    }

    public static void fun(Fruit fru) {
        fru.print("蘋果"); // 設置參數的內容
    }
}

範例:編寫多行語句

interface Fruit {
    public void print(String str); // 接口原本定義的方法
}

public class Demo {
    public static void main(String[] args) {
        // 首先要定義此表達式裏面需要接收變量,單行語句直接進行輸出
        fun((s) -> {
            s = s.toUpperCase();
            System.out.println(s);
        });
    }

    public static void fun(Fruit fru) {
        fru.print("Hello"); // 設置參數的內容
    }
}

範例:編寫表達式

interface Fruit {
    public int add(int x, int y);
}

public class Demo {
    public static void main(String[] args) {
        // 首先要定義此表達式裏面需要接收變量,單行語句直接進行輸出
        fun((s1, s2) -> s1 + s2);
    }

    public static void fun(Fruit fru) {
        System.out.println(fru.add(10, 20));
    }
}

方法引用

對象引用的特點:不同對象可以操作同一塊內容。而方法引用就是指爲一個方法設置別名,相當於一個方法定義了不同的名字。
1、方法引用在Java8中一共定義了四種形式:

· 引用靜態方法: 類名稱::static 方法名稱;
· 引用某個對象的方法:實例化對象::普通方法;
· 引用特定類型的方法:特定類::普通方法;
· 引用構造方法:類名稱::new。

範例:引用靜態方法
String類中的valueof():public static String valueof(int x)

package com.java.demo;

/**
 * 只有一個方法的接口
 * @param <P> 參數的數據類型
 * @param <R> 返回值的數據類型
 */
interface Math<P, R> {
    public R exchange(P p);
}

public class Demo {
    public static void main(String[] args) {
        // 覆寫了exchange(),使其具有valueOf()的功能
        Math<Integer, String> math = String::valueOf;
        String msg = math.exchange(10000);
        // 將所有的0替換成9
        System.out.println(msg.replaceAll("0", "9"));
    }
}

範例:普通方法引用
String類中的toUpperCase():public String toUpperCase()

package com.java.demo;

interface Math<R> {
    public R upper();
}

public class Demo {
    public static void main(String[] args) {
        // 覆寫了upper,使其具有toUpperCase的功能
        // toUpperCase是普通方法,必須由String對象調用
        // hello是String對象,代碼如下
        Math<String> math = "hello"::toUpperCase;
        String msg = math.upper();
        System.out.println(msg);
    }
}

上述例子顯示,要實現方法引用,必須要有接口,且該接口只能有一個方法。爲了保證該接口只有一個方法,可對其進行註解說明。

@FunctionalInterface // 此爲函數式接口,只能定義一個方法
interface ITest<R> {
    public R upper();
}

2、在進行方法引用的過程中,還有一種形式的引用(這種形式需要特定類的對象支持)。一般使用“類::方法”,引用的是類中的靜態方法。但是這種形式也可以引用普通方法。
例如:在String類中有一個方法:public int compareTo(String anotherString),比較的形式是String對象1.compareTo(String對象2),即要引用該方法,需要有兩個參數。
範例:引用特定類的方法

interface IMessage<P> {
    public int compare(P p1, P p2);
}

public class Demo {
    public static void main(String[] args) {
        IMessage<String> msg = String::compareTo;
        System.out.println(msg.compare("A", "B"));
    }
}

與之前相比,方法引用前不需要定義對象,可以理解爲將對象定義在參數上。
範例:引用構造方法

interface IMessage<C> {
    public C create(String t, double p);
}

class Book {
    private String title;
    private double price;

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    public String toString() {
        return "書名:" + this.title + ",價格:" + this.price;
    }
}

public class Demo {
    public static void main(String[] args) {
        IMessage<Book> msg = Book::new; // 引用構造方法
        // 雖然調用的是create(),實際引用了Book類的構造方法
        Book book = msg.create("Java開發", 66.6);
        System.out.println(book);
    }
}

對象引用是使用不同的名字,而方法引用需要一個函數接口。

內建函數式接口

1、JDK1.8中提供了一個包:java.util.function,提供有以下四個核心接口:

(1)功能性接口(Function):public interface Function<T,R>{public R apply(T t);}
|- 此接口需要接收一個參數,並且返回一個處理結果;
(2)消費型接口(Consumer):public interface Consumer{public void accept(T t);}
|- 此接口只負責接收數據(引用數據是不需要返回的),並且不返回結果;
(3)供給型接口(Suplier):public interface Supplier{public T get();}
|- 此接口不接收參數,但是可以返回結果
(4)斷言型接口(Predicate):public interface Predicate{public boolean Test(T t);}
|- 進行判斷操作使用;

在JDK1.8中存在以上四個功能型接口,所以很少會由用戶去定義新的函數式接口。
範例:函數式接口——接收參數並返回處理結果
· String類有一個方法:public boolean startsWith(String str)

package com.java.demo;

import java.util.function.Function;

public class Demo {
    public static void main(String[] args) {
        Function<String, Boolean> fun = "##hello"::startsWith;
        System.out.println(fun.apply("##")); // true
    }
}

範例:消費型接口

package com.java.demo;

import java.util.function.Consumer;

class MyDemo {
    // 此方法沒有返回值,但是有參數
    public void print(String str) {
        System.out.println(str);
    }
}

public class Demo {
    public static void main(String[] args) {
        Consumer<String> cons = new MyDemo()::print;
        cons.accept("Hello World");
    }
}

範例:供給型接口
· 引用String類的toUpperCase():public String toUpperCase();

package com.java.demo;

import java.util.function.Supplier;

public class Demo {
    public static void main(String[] args) {
        Supplier<String> sup = "hello"::toUpperCase;
        System.out.println(sup.get());
    }
}

範例:斷言型接口
· String類中有equalsIgnoreCase()

import java.util.function.Predicate;

public class Demo {
    public static void main(String[] args) {
        Predicate<String> pre = "hello"::equalsIgnoreCase;
        System.out.println(pre.test("Hello"));
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章