溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

java8新特性lambda表達(dá)式的語(yǔ)法是什么

發(fā)布時(shí)間:2023-03-13 13:58:04 來(lái)源:億速云 閱讀:98 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇“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á)式的語(yǔ)法

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í)減少了很多代碼的使用。

函數(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ù)式接口。

java8新特性lambda表達(dá)式的語(yǔ)法是什么

注意觀察該接口的源代碼,只包含一個(gè)抽象的方法的接口是函數(shù)式接口,下面andThen是一個(gè)默認(rèn)方法,并不屬于抽象方法。不要被迷惑了。

內(nèi)建函數(shù)式的接口

jdk8中默認(rèn)定義了很多函數(shù)式接口,主要使用的有下面四個(gè)。

函數(shù)式接口參數(shù)類型返回類型使用說(shuō)明
Consumer<T> 消費(fèi)型接口Tvoid對(duì)類型T的數(shù)據(jù)進(jìn)行操作,抽象方法 void accept(T t)
Supplier 供給型接口無(wú)T返回類型T的對(duì)象,抽象方法 T get();
Function<T,R> 函數(shù)型接口TR對(duì)類型T對(duì)象進(jìn)行操作,返回類型R的對(duì)象,抽象方法R apply(T t)
Predicate<T> 斷言型接口Tbolean對(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"));
    }

構(gòu)造器引用

這兒以函數(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è)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI