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