您好,登錄后才能下訂單哦!
這篇“java8新特性lambda表達(dá)式的語(yǔ)法是什么”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“java8新特性lambda表達(dá)式的語(yǔ)法是什么”文章吧。
jdk8發(fā)布新特性中,lambda是一大亮點(diǎn)之一。lambda表達(dá)式能夠簡(jiǎn)化我們對(duì)數(shù)據(jù)的操作,減少代碼量,大大提升我們的開(kāi)發(fā)效率。
Lambda 表達(dá)式”(lambda expression)是一個(gè)匿名函數(shù),Lambda表達(dá)式基于數(shù)學(xué)中的λ演算得名,直接對(duì)應(yīng)于其中的lambda抽象(lambda abstraction),是一個(gè)匿名函數(shù),即沒(méi)有函數(shù)名的函數(shù)。
Lambda表達(dá)式可以表示閉包。如果你之前了解scala和js函數(shù)式編程,將會(huì)更加快速上手和學(xué)習(xí)java8的lambda新特性。
Lambda表達(dá)式在Java8中引入了一個(gè)新的語(yǔ)法操作符號(hào),即:->
,它將Lambda表達(dá)式分為兩部分。
左側(cè)
Lambda表達(dá)式左側(cè)為入?yún)?shù)。
右側(cè)
Lambada表示式的右側(cè)表示執(zhí)行的功能。
總結(jié)就是:
(parameters) -> expression 或 (parameters) ->{ statements; }
以下是Lambda表達(dá)式幾種語(yǔ)法格式:
1.無(wú)參,無(wú)返回值,典型的一個(gè)例子是Runnable匿名內(nèi)部類的使用。
// java 8之前的寫(xiě)法 Runnable runnable = new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " >---Lambda"); } }; // 使用lambda的寫(xiě)法 Runnable r = () -> System.out.println(Thread.currentThread().getName() + " >---Lambda");
2.一個(gè)參數(shù)的使用
// java 8 之前的寫(xiě)法 Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; // Lambda表達(dá)式的寫(xiě)法 Consumer<String> consumer = (par)->System.out.println(par); consumer.accept("xixi"); 一個(gè)參數(shù)的小括號(hào)可以省略,簡(jiǎn)化如下: Consumer<String> consumer = par->System.out.println(par);
3.兩個(gè)參數(shù)的使用
// java 8之前的寫(xiě)法 Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }; // 使用Lambda表達(dá)式的方法 ,當(dāng)只有一條語(yǔ)句的時(shí)候,大括號(hào)和return都可以省略 Comparator<Integer> comparator=(x,y) -> x.compareTo(y);
觀察上面的代碼后,我們發(fā)現(xiàn)使用Lambda表達(dá)式,在Lambda表達(dá)式中并沒(méi)有指定入?yún)⒌膮?shù)類型。這個(gè)編譯和運(yùn)行沒(méi)有報(bào)錯(cuò),這個(gè)是怎么判斷出來(lái)的呢?
很簡(jiǎn)單是類型推斷的作用,java8中有個(gè)很大的變化,就是類型推斷,簡(jiǎn)單來(lái)說(shuō)javac在編譯代碼時(shí)候,會(huì)根據(jù)程序的上下文來(lái)推斷出Lambda表達(dá)式參數(shù)類型。
例如上文中的下面這個(gè)代碼:
Comparator<Integer> comparator=(x,y) -> x.compareTo(y);
這里在編譯的時(shí)候,在執(zhí)行x.compareTo(y)
的時(shí)候根據(jù)類型推斷,因?yàn)檫@個(gè)接口定義數(shù)據(jù)的泛型是Intger,所以根據(jù)類型推斷會(huì)自動(dòng)調(diào)用Integer.compareTo方法。
為理解lambda表達(dá)式的作用,以及簡(jiǎn)化我們開(kāi)發(fā)。這兒將會(huì)舉個(gè)小小的例子。
王小明所在的公司,每一個(gè)月都會(huì)進(jìn)行薪資財(cái)務(wù)報(bào)表,王小明每一個(gè)月都會(huì)自己對(duì)員工們的薪資做統(tǒng)計(jì),以了解公司財(cái)務(wù)支出和訂單提成等需求。常常有做訂單提成排名和總工資排名的這樣的一個(gè)需求。
我們將定義以下類,來(lái)完成王小明的統(tǒng)計(jì)需求。
基本員工類
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; } }
現(xiàn)在假設(shè)在A部門(mén)有,青龍,白虎,朱雀,玄武 四個(gè)部門(mén)人員。下面是他們上個(gè)月基本薪資的情況。
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);
現(xiàn)在有個(gè)統(tǒng)計(jì)的需求是,按員工年齡從小到大排列,并獲取員工姓名列表。讓我們分別使用Lambda表達(dá)式和java8之前的做法。
java8之前通常的做法
// 員工列表先進(jìn)行排序 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表達(dá)式使用的方便,確實(shí)減少了很多代碼的使用。
只包含一個(gè)抽象方法的接口,稱為函數(shù)式接口。
使用Lambda表達(dá)式創(chuàng)建該對(duì)象接口的對(duì)象,如果Lambda拋出一個(gè)受檢異常,通常需要在目標(biāo)接口使用@FunctionalInterface
注解,來(lái)聲明標(biāo)記了該注解的接口是一個(gè)函數(shù)式接口。
例如:
Consumer<String> consumer = par->System.out.println(par);
就是一個(gè)典型的消費(fèi)型函數(shù)式接口。
注意觀察該接口的源代碼,只包含一個(gè)抽象的方法的接口是函數(shù)式接口,下面andThen
是一個(gè)默認(rèn)方法,并不屬于抽象方法。不要被迷惑了。
內(nèi)建函數(shù)式的接口
jdk8中默認(rèn)定義了很多函數(shù)式接口,主要使用的有下面四個(gè)。
函數(shù)式接口 | 參數(shù)類型 | 返回類型 | 使用說(shuō)明 |
---|---|---|---|
Consumer<T> 消費(fèi)型接口 | T | void | 對(duì)類型T的數(shù)據(jù)進(jìn)行操作,抽象方法 void accept(T t) |
Supplier 供給型接口 | 無(wú) | T | 返回類型T的對(duì)象,抽象方法 T get(); |
Function<T,R> 函數(shù)型接口 | T | R | 對(duì)類型T對(duì)象進(jìn)行操作,返回類型R的對(duì)象,抽象方法R apply(T t) |
Predicate<T> 斷言型接口 | T | bolean | 對(duì)類型T對(duì)象進(jìn)行操作,返回類型boolean,抽象方法boolean test(T t) |
四大函數(shù)式接口的使用
public class FourFunctionsTest { // 消費(fèi)式接口 @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)); } // 函數(shù)式接口 @Test public void testFunction() { Function<Integer, Boolean> function = x -> x > 3; System.out.println(function.apply(4)); } }
自定義函數(shù)式接口
上面我們舉例A部門(mén)的四個(gè)員工,找出工資大于5000的員工。
// 使用策略式接口 @FunctionalInterface // 函數(shù)式接口(檢查)只能有一個(gè)抽象方法 public interface MyFilter<T> { /** * 獲取指定想要的employee對(duì)象 * * @param t * @return */ boolean getWant(T t); } /** * 策略設(shè)計(jì)模式 */ 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; } // 匿名內(nèi)部類 List<Employee> employees1 = needEmployee(employees, new MyFilter<Employee>() { @Override public boolean getWant(Employee employee) { return employee.getTotalSalary() >= 5000; } }); // 使用策略者設(shè)計(jì)模式Lambda簡(jiǎn)化 needEmployee(employees, employee -> mployee.getTotalSalary() >= 5000);
看了上面代碼,如果還想簡(jiǎn)化怎么做呢?這里可以使用java 8的Stream API可以大大簡(jiǎn)化以上繁多的代碼。
employees.stream().filter(e -> e.getTotalSalary() > 5000d).map(Employee::getName).forEach(System.out::println);
看到這兒,可能剛剛?cè)腴T(mén)的同學(xué)會(huì)懵逼,因?yàn)樯厦嬗昧薙tream相關(guān)的API以及(Employee::getName)
中::表示什么含義呢?別著急,慢慢往下看。
使用操作符::
將方法名和對(duì)象或者類的名字分隔開(kāi),組合有以下三種。
對(duì)象::實(shí)例方法名
類::靜態(tài)方法
類::實(shí)例方法
常見(jiàn)的x-> System.out.println()
等同于System.out::println。
注意:
Lambda 體中調(diào)用方法的參數(shù)列表與返回值類型,要與函數(shù)式接口抽象方法的該函數(shù)列表和返回值類型保持一致。
若Lambda參數(shù)列表中的第一個(gè)參數(shù)是實(shí)例方法的調(diào)用者,而第二個(gè)參數(shù)是實(shí)例方法的參數(shù)時(shí)??梢允褂?ClassName :: method
說(shuō)起來(lái)比較抽象,請(qǐng)看下面的例子。
// 對(duì)象::實(shí)例方法 @Test public void testConsumer() { Employee emp = new Employee(); // 函數(shù)式接口Supplier是空參,返回是Integer類型的接口, // 而對(duì)應(yīng)emp的實(shí)例方法getAge()剛剛好是空參且返回Integer類型的數(shù)據(jù),符合上面注意事項(xiàng)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); // 要求參數(shù)第一個(gè)值作為方法體的調(diào)用者,第二個(gè)參數(shù)值作為方法體的被調(diào)用者(參數(shù))符合注意事項(xiàng)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")); }
這兒以函數(shù)式接口為例:可以將返回的參數(shù)R,使用構(gòu)造器的構(gòu)造方法。
// 當(dāng)Employee有下面的構(gòu)造時(shí)候 public Employee(int age) { this.age = age; }
可構(gòu)造以下這樣的一個(gè)函數(shù)式接口。
Function<Integer,Employee> fun = i -> new Employee(i) System.out.println(fun.apply(13)); // 使用構(gòu)造器引用簡(jiǎn)化后: Function<Integer,Employee> fun = Employee::new System.out.println(fun.apply(15));
以上就是關(guān)于“java8新特性lambda表達(dá)式的語(yǔ)法是什么”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。