java8新特性之lambda表达式(及方法引用与构造器引用)
Lambda 允許把函數作為一個方法的參數(函數作為參數傳遞進方法中)。使用 Lambda 表達式可以使代碼變的更加簡潔緊湊。
一、語法
lambda 表達式的語法格式如下:
(parameters) -> expression 或 (parameters) ->{ statements; }以下是lambda表達式的重要特征:
二、Lambda 表達式實例
Lambda 表達式的簡單例子:
// 1. 不需要參數,返回值為 5 () -> 5 // 2. 接收一個參數(數字類型),返回其2倍的值 x -> 2 * x // 3. 接受2個參數(數字),并返回他們的差值 (x, y) -> x – y // 4. 接收2個int型整數,返回他們的和 (int x, int y) -> x + y // 5. 接受一個 string 對象,并在控制臺打印,不返回任何值(看起來像是返回void) (String s) -> System.out.print(s)在 Java8Tester.java 文件輸入以下代碼:
Java8Tester.java 文件
public class Java8Tester {public static void main(String args[]){Java8Tester tester = new Java8Tester();// 類型聲明MathOperation addition = (int a, int b) -> a + b;// 不用類型聲明MathOperation subtraction = (a, b) -> a - b;// 大括號中的返回語句MathOperation multiplication = (int a, int b) -> { return a * b; };// 沒有大括號及返回語句MathOperation division = (int a, int b) -> a / b;System.out.println("10 + 5 = " + tester.operate(10, 5, addition));System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));System.out.println("10 / 5 = " + tester.operate(10, 5, division));// 不用括號GreetingService greetService1 = message ->System.out.println("Hello " + message);// 用括號GreetingService greetService2 = (message) ->System.out.println("Hello " + message);greetService1.sayMessage("Runoob");greetService2.sayMessage("Google");}interface MathOperation {int operation(int a, int b);}interface GreetingService {void sayMessage(String message);}private int operate(int a, int b, MathOperation mathOperation){return mathOperation.operation(a, b);} }執行以上腳本,輸出結果為:
$ javac Java8Tester.java $ java Java8Tester 10 + 5 = 15 10 - 5 = 5 10 x 5 = 50 10 / 5 = 2 Hello Runoob Hello Google三、使用 Lambda 表達式需要注意以下兩點
變量作用域
在 Java8Tester.java 文件輸入以下代碼:
Java8Tester.java 文件
public class Java8Tester {final static String salutation = "Hello! ";public static void main(String args[]){GreetingService greetService1 = message -> System.out.println(salutation + message);greetService1.sayMessage("Runoob");}interface GreetingService {void sayMessage(String message);} }執行以上腳本,輸出結果為:
$ javac Java8Tester.java $ java Java8Tester Hello! Runoob我們也可以直接在 lambda 表達式中訪問外層的局部變量:
Java8Tester.java 文件
public class Java8Tester {public static void main(String args[]) {final int num = 1;Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));s.convert(2); // 輸出結果為 3}public interface Converter<T1, T2> {void convert(int i);} }lambda 表達式的局部變量可以不用聲明為 final,但是必須不可被后面的代碼修改(即隱性的具有 final 的語義)
int num = 1; Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); s.convert(2); num = 5; //報錯信息:Local variable num defined in an enclosing scope must be final or effectively final 在 Lambda 表達式當中不允許聲明一個與局部變量同名的參數或者局部變量。String first = ""; Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length()); //編譯會出錯四、lambda表達式的常見使用場景
對一個列表的每一個元素進行操作,不使用 Lambda 表達式時如下:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); for (int element : numbers) {System.out.prinln(element); }使用 Lambda 表達式:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.forEach(x -> System.out.println(x));如果只需要調用單個函數對列表元素進行處理,那么可以使用更加簡潔的 方法引用 代替 Lambda 表達式:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.forEach(System.out::println);不使用 Lambda 表達式:
button.addActionListener(new ActionListener(){@Overridepublic void actionPerformed(ActionEvent e) {//handle the event} });使用 Lambda 表達式,需要編寫多條語句時用花括號包圍起來:
button.addActionListener(e -> {//handle the event });java.util.function 包中的 Predicate 接口可以很方便地用于過濾。如果你需要對多個對象進行過濾并執行相同的處理邏輯,那么可以將這些相同的操作封裝到 filter 方法中,由調用者提供過濾條件,以便重復使用。
不使用 Predicate 接口,對于每一個對象,都需要編寫過濾條件和處理邏輯:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<String> words = Arrays.asList("a", "ab", "abc");numbers.forEach(x -> {if (x % 2 == 0) {//process logic} }) words.forEach(x -> {if (x.length() > 1) {//process logic} })使用 Predicate 接口,將相同的處理邏輯封裝到 filter 方法中,重復調用:
public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);List<String> words = Arrays.asList("a", "ab", "abc");filter(numbers, x -> (int)x % 2 == 0);filter(words, x -> ((String)x).length() > 1); }public static void filter(List list, Predicate condition) {list.forEach(x -> {if (condition.test(x)) {//process logic}}) }filter 方法也可寫成:
public static void filter(List list, Predicate condition) {list.stream().filter(x -> condition.test(x)).forEach(x -> {//process logic}) }使用 Stream 對象的 map 方法將原來的列表經由 Lambda 表達式映射為另一個列表,并通過 collect 方法轉換回 List 類型:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<Integer> mapped = numbers.stream().map(x -> x * 2).collect(Collectors.toList()); mapped.forEach(System.out::println);reduce 操作,就是通過二元運算對所有元素進行聚合,最終得到一個結果。例如使用加法對列表進行聚合,就是將列表中所有元素累加,得到總和。因此,我們可以為 reduce 提供一個接收兩個參數的 Lambda 表達式,該表達式就相當于一個二元運算:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream().reduce((x, y) -> x + y).get(); System.out.println(sum);以創建線程為例,使用 Runnable 類的代碼如下:
Runnable r = new Runnable() {@Overridepublic void run() {//to do something} }; Thread t = new Thread(r); t.start();使用 Lambda 表達式:
Runnable r = () -> {//to do something }; Thread t = new Thread(r); t.start();或者使用更加緊湊的形式:
Thread t = new Thread(() -> {//to do something }); t.start;五、方法引用
方法引用是對Lambda表達式符合某種情況下的一種縮寫,使得我們的Lambda表達式更加的精簡, 也可以理解為Lambda表達式的另一種表現形式(縮寫)
當要傳遞給Lambda體內的操作,已經有實現的方法了,就可以使用方法引用了
1.方法引用所引用的方法的參數列表必須要和函數式接口中抽象方法的參數列表相同(完全一致)
2.方法引用所引用的方法的的返回值必須要和函數式接口中抽象方法的返回值相同(完全一致)
方法引用一般有三種格式:
1. 實例對象名::實例方法名
2. 類名::靜態方法名
3. 類名::實例方法名 (注意區別2,3的區別,下面會說)
2,3的區別:
若Lambda 的參數列表的第一個參數,是實例方法的調用者,第二個參數(或無參)是實例方法的參數時,格式: 類名::實例方法名
- 舉例一:1. 實例對象名::實例方法名(案例一)
- 舉例一: 1. 實例對象名::實例方法名 (案例二)
- 舉例二: 2. 類名::靜態方法名
- 舉例三: 3. 類名::實例方法名
六、構造器引用
與函數式接口相結合,自動與函數式接口中方法兼容。
可以把構造器引用賦值給定義的方法。
在使用Lambda表達的時,滿足使用構造器引用條件的時候可以使用
構造器參數列表要與接口中抽象方法的參數列表一致!
語法格式:
類名 :: new
七、數組引用
這里單獨把數組引用拿出來實際上是強調一下,數組引用和構造引用基本相同,直接上一個案例來說明問題
文章轉自
文章轉自
文章轉自
總結
以上是生活随笔為你收集整理的java8新特性之lambda表达式(及方法引用与构造器引用)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021年中国养老前景调查报告
- 下一篇: Java8新特性之stream的详细用法