您好,登錄后才能下訂單哦!
這篇“java8新特性lambda表達式的語法是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“java8新特性lambda表達式的語法是什么”文章吧。
jdk8發布新特性中,lambda是一大亮點之一。lambda表達式能夠簡化我們對數據的操作,減少代碼量,大大提升我們的開發效率。
Lambda 表達式”(lambda expression)是一個匿名函數,Lambda表達式基于數學中的λ演算得名,直接對應于其中的lambda抽象(lambda abstraction),是一個匿名函數,即沒有函數名的函數。
Lambda表達式可以表示閉包。如果你之前了解scala和js函數式編程,將會更加快速上手和學習java8的lambda新特性。
Lambda表達式在Java8中引入了一個新的語法操作符號,即:->
,它將Lambda表達式分為兩部分。
左側
Lambda表達式左側為入參參數。
右側
Lambada表示式的右側表示執行的功能。
總結就是:
(parameters) -> expression 或 (parameters) ->{ statements; }
以下是Lambda表達式幾種語法格式:
1.無參,無返回值,典型的一個例子是Runnable匿名內部類的使用。
// java 8之前的寫法 Runnable runnable = new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " >---Lambda"); } }; // 使用lambda的寫法 Runnable r = () -> System.out.println(Thread.currentThread().getName() + " >---Lambda");
2.一個參數的使用
// java 8 之前的寫法 Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; // Lambda表達式的寫法 Consumer<String> consumer = (par)->System.out.println(par); consumer.accept("xixi"); 一個參數的小括號可以省略,簡化如下: Consumer<String> consumer = par->System.out.println(par);
3.兩個參數的使用
// java 8之前的寫法 Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }; // 使用Lambda表達式的方法 ,當只有一條語句的時候,大括號和return都可以省略 Comparator<Integer> comparator=(x,y) -> x.compareTo(y);
觀察上面的代碼后,我們發現使用Lambda表達式,在Lambda表達式中并沒有指定入參的參數類型。這個編譯和運行沒有報錯,這個是怎么判斷出來的呢?
很簡單是類型推斷的作用,java8中有個很大的變化,就是類型推斷,簡單來說javac在編譯代碼時候,會根據程序的上下文來推斷出Lambda表達式參數類型。
例如上文中的下面這個代碼:
Comparator<Integer> comparator=(x,y) -> x.compareTo(y);
這里在編譯的時候,在執行x.compareTo(y)
的時候根據類型推斷,因為這個接口定義數據的泛型是Intger,所以根據類型推斷會自動調用Integer.compareTo方法。
為理解lambda表達式的作用,以及簡化我們開發。這兒將會舉個小小的例子。
王小明所在的公司,每一個月都會進行薪資財務報表,王小明每一個月都會自己對員工們的薪資做統計,以了解公司財務支出和訂單提成等需求。常常有做訂單提成排名和總工資排名的這樣的一個需求。
我們將定義以下類,來完成王小明的統計需求。
基本員工類
package com.codegeek.lambda; import lombok.*; @Setter @Getter @NoArgsConstructor @ToString public class Employee { /** * 員工姓名 */ private String name; /** * 員工年齡 */ private int age; /** * 基本薪水 */ private double basicSalary; /** * 訂單成交總額 */ private double dealTotalPrice; public Employee(String name, int age, double basicSalary,double dealTotalPrice) { this.name = name; this.age = age; this.basicSalary = basicSalary; this.dealTotalPrice = dealTotalPrice; } /** * 員工總薪資 * * @return Double */ public Double getTotalSalary() { return this.basicSalary + this.dealTotalPrice * 0.04; } }
現在假設在A部門有,青龍,白虎,朱雀,玄武 四個部門人員。下面是他們上個月基本薪資的情況。
Employee qingLong = new Employee("青龍", 25, 5500, 7500); Employee baiHu = new Employee("白虎", 27, 5000, 9000); Employee zhuQue = new Employee("朱雀", 22, 3800, 4500); Employee xuanWu = new Employee("玄武", 24, 3300, 3300); List<Employee> employees = Arrays.asList(qingLong, baiHu, zhuQue, xuanWu);
現在有個統計的需求是,按員工年齡從小到大排列,并獲取員工姓名列表。讓我們分別使用Lambda表達式和java8之前的做法。
java8之前通常的做法
// 員工列表先進行排序 employees.sort(new Comparator<Employee>() { @Override public int compare(Employee o1, Employee o2) { Integer age1 = o1.getAge(); Integer age2 = o2.getAge(); return age1.compareTo(age2); } }); // 遍歷排序后的列表并輸出員工姓名 for (Employee employee : employees) { System.out.println(employee.getName()); }
使用Lambda的做法
employees.stream().sorted((o1, o2) -> o1.getAge().compareTo(o2.getAge())) .forEach(o -> System.out.println(o.getName()));
看到這里我們一定知道Lambda表達式使用的方便,確實減少了很多代碼的使用。
只包含一個抽象方法的接口,稱為函數式接口。
使用Lambda表達式創建該對象接口的對象,如果Lambda拋出一個受檢異常,通常需要在目標接口使用@FunctionalInterface
注解,來聲明標記了該注解的接口是一個函數式接口。
例如:
Consumer<String> consumer = par->System.out.println(par);
就是一個典型的消費型函數式接口。
注意觀察該接口的源代碼,只包含一個抽象的方法的接口是函數式接口,下面andThen
是一個默認方法,并不屬于抽象方法。不要被迷惑了。
內建函數式的接口
jdk8中默認定義了很多函數式接口,主要使用的有下面四個。
函數式接口 | 參數類型 | 返回類型 | 使用說明 |
---|---|---|---|
Consumer<T> 消費型接口 | T | void | 對類型T的數據進行操作,抽象方法 void accept(T t) |
Supplier 供給型接口 | 無 | T | 返回類型T的對象,抽象方法 T get(); |
Function<T,R> 函數型接口 | T | R | 對類型T對象進行操作,返回類型R的對象,抽象方法R apply(T t) |
Predicate<T> 斷言型接口 | T | bolean | 對類型T對象進行操作,返回類型boolean,抽象方法boolean test(T t) |
四大函數式接口的使用
public class FourFunctionsTest { // 消費式接口 @Test public void testConsumer() { Consumer<Integer> consumer = x -> System.out.println(x); consumer.accept(1); } // 供給式接口 @Test public void testSupplier() { Supplier<String> supplier = () -> { StringBuffer sb = new StringBuffer(); return sb.append("我").append(520).append("you").toString(); }; System.out.println(supplier.get()); } // 斷言式接口 @Test public void testPredicate() { Predicate<Long> predicate = x -> x == 1L; System.out.println(predicate.test(2L)); } // 函數式接口 @Test public void testFunction() { Function<Integer, Boolean> function = x -> x > 3; System.out.println(function.apply(4)); } }
自定義函數式接口
上面我們舉例A部門的四個員工,找出工資大于5000的員工。
// 使用策略式接口 @FunctionalInterface // 函數式接口(檢查)只能有一個抽象方法 public interface MyFilter<T> { /** * 獲取指定想要的employee對象 * * @param t * @return */ boolean getWant(T t); } /** * 策略設計模式 */ public List<Employee> needEmployee(List<Employee> employeeList, MyFilter<Employee> filter) { List<Employee> employees = new ArrayList<>(); for (Employee employee : employeeList) { if (filter.getWant(employee)) { employees.add(employee); } } return employees; } // 匿名內部類 List<Employee> employees1 = needEmployee(employees, new MyFilter<Employee>() { @Override public boolean getWant(Employee employee) { return employee.getTotalSalary() >= 5000; } }); // 使用策略者設計模式Lambda簡化 needEmployee(employees, employee -> mployee.getTotalSalary() >= 5000);
看了上面代碼,如果還想簡化怎么做呢?這里可以使用java 8的Stream API可以大大簡化以上繁多的代碼。
employees.stream().filter(e -> e.getTotalSalary() > 5000d).map(Employee::getName).forEach(System.out::println);
看到這兒,可能剛剛入門的同學會懵逼,因為上面用了Stream相關的API以及(Employee::getName)
中::表示什么含義呢?別著急,慢慢往下看。
使用操作符::
將方法名和對象或者類的名字分隔開,組合有以下三種。
對象::實例方法名
類::靜態方法
類::實例方法
常見的x-> System.out.println()
等同于System.out::println。
注意:
Lambda 體中調用方法的參數列表與返回值類型,要與函數式接口抽象方法的該函數列表和返回值類型保持一致。
若Lambda參數列表中的第一個參數是實例方法的調用者,而第二個參數是實例方法的參數時。可以使用 ClassName :: method
說起來比較抽象,請看下面的例子。
// 對象::實例方法 @Test public void testConsumer() { Employee emp = new Employee(); // 函數式接口Supplier是空參,返回是Integer類型的接口, // 而對應emp的實例方法getAge()剛剛好是空參且返回Integer類型的數據,符合上面注意事項1的要求 Supplier<Integer> supplier = () -> emp.getAge(); Supplier<Double> sup2 = emp::getSalary; System.out.println(supplier.get()); } // 類::方法名 @Test public void testSupplier() { Comparator<String> comparator = (x, y) -> x.compareTo(y); // 要求參數第一個值作為方法體的調用者,第二個參數值作為方法體的被調用者(參數)符合注意事項2的要求 Comparator<String> compString = String::compareTo; System.out.println(comparator.compare("2", "3")); Comparator<Integer> com = Integer::compare; System.out.println(com.compare(1, 2)); BiPredicate<String, String> predicate = String::equals; System.out.println(predicate.test("we", "eq")); }
這兒以函數式接口為例:可以將返回的參數R,使用構造器的構造方法。
// 當Employee有下面的構造時候 public Employee(int age) { this.age = age; }
可構造以下這樣的一個函數式接口。
Function<Integer,Employee> fun = i -> new Employee(i) System.out.println(fun.apply(13)); // 使用構造器引用簡化后: Function<Integer,Employee> fun = Employee::new System.out.println(fun.apply(15));
以上就是關于“java8新特性lambda表達式的語法是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。