1. 程式人生 > >Lambda表示式和匿名內部類(I)

Lambda表示式和匿名內部類(I)

前言

Java Lambda表示式的一個重要用法是簡化某些匿名內部類Anonymous Classes)的寫法。實際上Lambda表示式並不僅僅是匿名內部類的語法糖,JVM內部是通過invokedynamic指令來實現Lambda表示式的。具體原理放到下一篇。本篇我們首先感受一下使用Lambda表示式帶來的便利之處。

取代某些匿名內部類

本節將介紹如何使用Lambda表示式簡化匿名內部類的書寫,但Lambda表示式並不能取代所有的匿名內部類,只能用來取代函式介面(Functional Interface)的簡寫。先別在乎細節,看幾個例子再說。

例子1:無參函式的簡寫

如果需要新建一個執行緒,一種常見的寫法是這樣:

// JDK7 匿名內部類寫法
new Thread(new Runnable(){// 介面名
    @Override
    public void run(){// 方法名
        System.out.println("Thread run()");
    }
}).start();

上述程式碼給Tread類傳遞了一個匿名的Runnable物件,過載Runnable介面的run()方法來實現相應邏輯。這是JDK7以及之前的常見寫法。匿名內部類省去了為類起名字的煩惱,但還是不夠簡化,在Java 8中可以簡化為如下形式:

// JDK8 Lambda表示式寫法
new Thread(
        () -> System.out.println("Thread run()")// 省略介面名和方法名
).start();

上述程式碼跟匿名內部類的作用是一樣的,但比匿名內部類更進一步。這裡連介面名和函式名都一同省掉了,寫起來更加神清氣爽。如果函式體有多行,可以用大括號括起來,就像這樣:

// JDK8 Lambda表示式程式碼塊寫法
new Thread(
        () -> {
            System.out.print("Hello");
            System.out.println(" Hoolee");
        }
).start();

例子2:帶參函式的簡寫

如果要給一個字串列表通過自定義比較器,按照字串長度進行排序,Java 7的書寫形式如下:

// JDK7 匿名內部類寫法
List<String> list = Arrays.asList("I", "love", "you", "too");
Collections.sort(list, new Comparator<String>(){// 介面名
    @Override
    public int compare(String s1, String s2){// 方法名
        if(s1 == null)
            return -1;
        if(s2 == null)
            return 1;
        return s1.length()-s2.length();
    }
});

上述程式碼通過內部類過載了Comparator介面的compare()方法,實現比較邏輯。採用Lambda表示式可簡寫如下:

// JDK8 Lambda表示式寫法
List<String> list = Arrays.asList("I", "love", "you", "too");
Collections.sort(list, (s1, s2) ->{// 省略引數表的型別
    if(s1 == null)
        return -1;
    if(s2 == null)
        return 1;
    return s1.length()-s2.length();
});

上述程式碼跟匿名內部類的作用是一樣的。除了省略了介面名和方法名,程式碼中把引數表的型別也省略了。這得益於javac型別推斷機制,編譯器能夠根據上下文資訊推斷出引數的型別,當然也有推斷失敗的時候,這時就需要手動指明引數型別了。注意,Java是強型別語言,每個變數和物件都必需有明確的型別。

簡寫的依據

也許你已經想到了,能夠使用Lambda的依據是必須有相應的函式介面(函式介面,是指內部只有一個抽象方法的介面)。這一點跟Java是強型別語言吻合,也就是說你並不能在程式碼的任何地方任性的寫Lambda表示式。實際上Lambda的型別就是對應函式介面的型別Lambda表示式另一個依據是型別推斷機制,在上下文資訊足夠的情況下,編譯器可以推斷出引數表的型別,而不需要顯式指名。Lambda表達更多合法的書寫形式如下:

// Lambda表示式的書寫形式
Runnable run = () -> System.out.println("Hello World");// 1
ActionListener listener = event -> System.out.println("button clicked");// 2
Runnable multiLine = () -> {// 3 程式碼塊
    System.out.print("Hello");
    System.out.println(" Hoolee");
};
BinaryOperator<Long> add = (Long x, Long y) -> x + y;// 4
BinaryOperator<Long> addImplicit = (x, y) -> x + y;// 5 型別推斷

上述程式碼中,1展示了無參函式的簡寫;2處展示了有參函式的簡寫,以及型別推斷機制;3是程式碼塊的寫法;4和5再次展示了型別推斷機制。

自定義函式介面

自定義函式介面很容易,只需要編寫一個只有一個抽象方法的介面即可。

// 自定義函式介面
@FunctionalInterface
public interface ConsumerInterface<T>{
    void accept(T t);
}

上面程式碼中的@FunctionalInterface是可選的,但加上該標註編譯器會幫你檢查介面是否符合函式介面規範。就像加入@Override標註會檢查是否過載了函式一樣。

有了上述介面定義,就可以寫出類似如下的程式碼:

ConsumerInterface<String> consumer = str -> System.out.println(str);

進一步的,還可以這樣使用:

class MyStream<T>{
    private List<T> list;
    ...
    public void myForEach(ConsumerInterface<T> consumer){// 1
        for(T t : list){
            consumer.accept(t);
        }
    }
}
MyStream<String> stream = new MyStream<String>();
stream.myForEach(str -> System.out.println(str));// 使用自定義函式介面書寫Lambda表示式

參考文獻

相關推薦

Lambda表示式匿名部類(I)

前言 Java Lambda表示式的一個重要用法是簡化某些匿名內部類(Anonymous Classes)的寫法。實際上Lambda表示式並不僅僅是匿名內部類的語法糖,JVM內部是通過invokedynamic指令來實現Lambda表示式的。具體原理放到下一篇。本篇我們首先感受一下使用Lambda表示式帶來

lambda表示式代替匿名部類

1、project的build檔案中新增classpath: classpath 'me.tatarka:gradle-retrolambda:3.2.0' 2、module的build檔案開頭新增apply:(android 3.0以上的版本跳過此步)

Lambda表達式匿名部類的異同

只有一個 lam fec system 一個 turn def () RR   Lambda表達式和匿名內部類的相同點: 都可以直接訪問成員變量,effectively final變量 Lambda表達式返回的對象和匿名內部類創建的對象一樣,可以調用繼承自接口的defau

java基礎15 部類(成員部類、局部內部類)匿名部類

body static 目前 還需 sleep imp 右下角 你好 private 一、內部類 1.1.1、成員內部類 一個類定義在另一個類的內部,那麽該類就叫作成員內部類 1.1.2、成員內部類訪問方式 方式一:在外部類中提供一個方法創建內部類的對

第38節:hashCode()與toString()與equals()函數的作用,部類匿名部類

指向 它的 函數 ati 使用外部 開發 算法 博客 else hashCode()和toString() Hash算法是把任意長度的數據通過hash算法成為散列值 hashCode() public int hashCode(){ int result = 10;

多執行緒匿名部類的理解

多執行緒 一.多執行緒 好處:提高任務的執行效率 (執行緒本身也會耗費系統資源 建立執行緒要把握度) 程序:一個正在執行的程式 一個程序可以有一個或多個執行緒 分時排程:cpu同

java之執行緒建立的兩種方式,六種狀態匿名部類建立子類或實現類物件

一.匿名內部類建立子類或實現類物件 new Test(){} 相當於建立了Test類的子類物件 並且沒有類名 建立介面實現類 new 介面名() {};介面實現類的物件 注意 : new 後邊是類或者介面名 大括號內是類或者介面中的方法 public

Java提高篇(三):部類匿名部類

1 public class innerclass { 2 public static void main(String[] args) { 3 System.out.println("下面是是內部類的程式展示"); 4 //建立外部類和內部類的方法有點不相同

Java static匿名部類

-- static Java中,任何變數 / 程式碼儲存時,都是 在編譯時 由系統自動分配記憶體; 在靜態變數編譯後,所分配的記憶體會一直存在,直到程式退出記憶體才會釋放這個空間; 類載入時,JVM會把靜態變數放到 方法區,被本類 & 本類的所有例項所共用。 --

【JAVA】執行緒建立匿名部類

前言 看多執行緒時,發現一些匿名內部類的東西,然後就來總結一下。   1.繼承Thread類 在類上實現匿名內部類 public class Demo1 { public static void main(String[] args) { Thread t = new T

Java 部類匿名部類

Java內部類和匿名內部類 1、內部類 一個類定義在另外一個類的內部,這個該類就被稱為內部類。內部類分為成員內部類(定義在外部類的成員位置)和區域性內部類(定義在外部類的方法裡面)。 (1)成員內部類

JAVA中部類匿名部類的區別,分別在什麼時候使用它們?

今天沒事,抽出時間總結了一下很多開發人員都想弄明白的一些JAVA基礎知識(內部類和匿名內部類)。 一、JAVA中內部類和匿名內部類的區別          內部類:內部類可以是static的或者非static的,static內部類只能包含靜態方法和靜態類變數,只能訪問外部類的

Java部類匿名部類的區別

很多初學者在對於內部類和匿名內部類的理解上給混淆了,其實是一個很容易理解的概念 1.什麼是類,類可以理解為一個物件。(那麼各位友友們思考,我們為什麼需要一個物件?因為我們需要這個物件去完成某中事情) 2.什麼是內部類呢?內部類就是在類的內部建立一個類,為什麼我們要

JAVA中的匿名類、部類匿名部類

   在看《java核心技術卷I》的時候再TreeSet的章節,看到了使用匿名內部類的例項,好奇後查了下相關資訊,有兩個部落格寫的很好,以後還需細看 先說下TreeSet的Test, TreeSet和Hashset的區別主要是前者是一個有序集合,使用的排序方法時紅黑

JAVA中區域性部類匿名部類的特點作用?

Java 內部類 分四種:成員內部類、區域性內部類、靜態內部類和匿名內部類。 1、成員內部類: 即作為外部類的一個成員存在,與外部類的屬性、方法並列。 注意:成員內部類中不能定義靜態變數,但可以訪問外部類的所有成員。 public class Outer{ privat

成員部類、靜態部類、區域性部類匿名部類的理解

說起內部類這個詞,想必很多人都不陌生,但是又會覺得不熟悉。原因是平時編寫程式碼時可能用到的場景不多,用得最多的是在有事件監聽的情況下,並且即使用到也很少去總結內部類的用法。今天我們就來一探究竟。下面是本文的目錄大綱:   一.內部類基礎   二.深入理解內部類   三.內部類的使用場景和好處   四.常見的與

Java部類詳解 及 區域性部類匿名部類只能訪問區域性final變數的原因

說起內部類這個詞,想必很多人都不陌生,但是又會覺得不熟悉。原因是平時編寫程式碼時可能用到的場景不多,用得最多的是在有事件監聽的情況下,並且即使用到也很少去總結內部類的用法。今天我們就來一探究竟。下面是本文的目錄大綱:   一.內部類基礎   二.深入理解內部類   三.內部類的使用場景和好處   

部類匿名部類

A.javainterface A { public void doSomething(); } AImpl.java class AImpl implements A { public void doSomething() { System.out.prin

Java之區域性部類匿名部類的區別詳解(附原始碼)

前言        前面提到過,可以在程式碼塊裡建立內部類,典型的方式是在一個方法體裡面建立。區域性內部類不能有訪問說明符,因為它不是外圍類的一部分;但是他可以訪問當前程式碼塊內的常量,以及此外圍類

java區域性部類匿名部類的比較

區域性內部類和匿名內部類,具有相同的能力和作用,但區域性內部類的名字在方法外是不可見的。 那麼為什麼我們使用區域性內部類而不是匿名內部類呢? * 唯一理由是:我們需要一個命名的構造器或者需要過載構造器