2013年3月27日 星期三

functional interface:Java 8 重新製作的概念

原文網址:http://www.javacodegeeks.com/2013/03/introduction-to-functional-interfaces-a-concept-recreated-in-java-8.html

下面這些 interface,全世界各地的 Java 開發人員至少用過一個以上: java.lang.Runnablejava.awt.event.ActionListenerjava.util.Comparatorjava.util.concurrent.Callable。 上述這些 interface 當中有一個共同的特點,就是它們只定義了一個 method。 JDK 當中有一堆這樣的 interface、Java 開發人員也製造了一堆。 這些 interface 也被稱為 Single Abstract Method interface(SAM interface)。 普遍常見的用法是產生一個 anonymous inner class 來使用這些 interface:

public class AnonymousInnerClassTest {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("A thread created and running ...");
            }
        }).start();
    }
}

在 Java 8 當中,SAM interface 的概念被重新製作,取名叫作 functional interface。 method reference 跟 constructor reference 可以用 lambda expression 來呈現 (我接下來的 blog 文章會涵蓋這兩個主題)。 在這裡導入了一個 annotation:@FunctionalInterface, 當你在一個不是 functional interface 的 interface 用這個 annotation, compiler 就會炸錯誤。 讓我們來看一下一個簡單的 functional interface,裡頭只有一個 abstract method:

@FunctionalInterface
public interface SimpleFuncInterface {
    public void doWork();
}

這個 interface 也可以把 java.lang.Object 的 method 宣告成 abstract method, 但依然是個 functional interface:

@FunctionalInterface
public interface SimpleFuncInterface {
    public void doWork();
    public String toString();
    public boolean equals(Object o);
}

一旦你加了另一個 abstract method 進去,compiler 或是 IDE 就會標示錯誤, 像下面這張圖這樣:

IDE error

interface 如果繼承另一個 functional interface, 而且沒有宣告任何新的 abstract method, 那麼新的 interface 仍然是 functional interface。 另一種情況是 interface 當中如果有一個 abstract method、 以及任意數量的 default method, 這個 interface 依然是 functional interface。 想了解 default method 可以看這篇文章

@FunctionalInterface
public interface ComplexFunctionalInterface extends SimpleFuncInterface {
    default public void doSomeWork(){
        System.out.println("Doing some work in interface impl...");
    }
    default public void doSomeOtherWork(){
        System.out.println("Doing some other work in interface impl...");
    }
}

上面這個 interface 仍然是一個有效的 functional interface。 現在我們來看看如何用 lambda expression 實作 function interface, 做出 anonymous inner class 的效果:

/*
* 比對用 anonymous inner class 以及 lambda expression 的實作方式
*/
public class SimpleFunInterfaceTest {
    public static void main(String[] args) {
        carryOutWork(new SimpleFuncInterface() {
            @Override
            public void doWork() {
                System.out.println("Do work in SimpleFun impl...");
            }
        });
        carryOutWork(() -> System.out.println("Do work in lambda exp impl..."));
    }
    public static void carryOutWork(SimpleFuncInterface sfi){
        sfi.doWork();
    }
}

程式輸出會長這樣:

Do work in SimpleFun impl...
Do work in lambda exp impl...

如果你用有支援 Java lambda expression 語法的 IDE(Netbeans 8 Nightly build), 那麼以上面的例子來說,會在 anonymous inner class 提供一個提示訊息:

IDE hint

這篇文章簡單地介紹了 Java 8 當中 functional interface 的觀念, 以及如何用 lambda expression 實作。

沒有留言:

張貼留言