Java lambda表达式用法介绍

Java
333
0
0
2023-06-08

在本文中,我们将通过示例了解Java Lambda表达式 以及lambda表达式在函数接口、通用函数接口和流API中的使用。

lambda表达式是在Java8中首次引入的。它的主要目标是提高语言的表达能力。

但是,在进入lambdas之前,我们首先需要了解功能接口。

什么是Functional Interface?

如果 Java接口 包含一个且仅包含一个抽象方法,则称为函数接口。只有一种方法指定了接口的预期用途。

例如,包 Java .lang 中的 Runnable 接口;是一个函数接口,因为它只构成一个方法,即 run()

示例1:用java定义函数接口

 import java.lang.FunctionalInterface;
@FunctionalInterface
public interface MyInterface{
    // the single abstract method
    double getValue();
} 

在上面的示例中,接口 MyInterface 只有一个抽象方法 getValue() 。因此,它是一个功能接口。

这里,我们使用了注释 @functioninterface 。注释强制Java编译器指示该接口是功能接口。因此,不允许有多个抽象方法。然而,这不是强制性的。

在Java7中,函数接口被视为单一抽象方法或SAM类型。SAMs通常在Java7中使用匿名类实现。

示例2:用java中的匿名类实现SAM

 public class FunctionInterfaceTest {
    public static void main(String[] args) {

        // anonymous class
        new Thread(new Runnable() {
            @ Override 
            public void run() {
                System.out.println("I just implemented the Runnable Functional Interface.");
            }
        }).start();
    }
} 

输出:

  just implemented the Runnable Functional Interface. 

在这里,我们可以将一个匿名类传递给一个方法。这有助于在Java7中编写代码更少的程序。但是,语法仍然很难,需要很多额外的代码行。

Java8进一步扩展了SAMs的功能。因为我们知道函数接口只有一个方法,所以在将其作为参数传递时,不需要定义该方法的名称。Lambda表达式允许我们完全做到这一点。

Lambda表达式简介

lambda表达式 本质上是一个匿名或未命名的方法。lambda表达式不会自行执行。相反,它用于实现由函数接口定义的方法。

如何在Java中定义lambda表达式?

下面是如何在Java中定义lambda表达式。

 (parameter list) -> lambda body 

使用的新运算符 (->) 称为箭头运算符或lambda运算符。语法目前可能不清楚。让我们来探讨一些例子,

假设我们有这样一种方法:

 double getPiValue() {
    return.1415;
} 

我们可以使用lambda表达式编写此方法,如下所示:

 () ->.1415 

这里,该方法没有任何参数。因此, 运算符 的左侧包含一个空参数。右侧是lambda主体,指定lambda表达式的操作。在本例中,它返回值3.1415。

Lambda体的类型

在Java中,lambda主体有两种类型。

  1. 具有单个表达式的主体
 () -> System.out.println("Lambdas are great"); 

这种类型的lambda体称为表达式体。

  1. 由代码块组成的主体。
 () -> {
    double pi =.1415;
    return pi;
}; 

这种类型的lambda体称为块体。块体允许lambda体包含多个语句。这些语句包含在大括号内,必须在大括号后添加分号。

注意:对于块体,如果块体返回值,则可以使用return语句。但是,表达式体不需要返回语句。

示例3:Lambda表达式

让我们编写一个Java程序,使用lambda表达式返回Pi的值。

如前所述,lambda表达式不会单独执行。相反,它形成了由函数接口定义的抽象方法的实现。

因此,我们需要首先定义一个功能接口。

 import java.lang.FunctionalInterface;

// this is functional interface
@FunctionalInterface
interface MyInterface{

    // abstract method
    double getPiValue();
}

public class Main {

    public static void main( String[] args ) {

    // declare a reference to MyInterface
    MyInterface ref;
    
    // lambda expression
    ref = () ->.1415;
    
    System.out.println("Value of Pi = " + ref.getPiValue());
    } 
} 

输出:

 Value of Pi =.1415 

在上面的例子中,

我们已经创建了一个名为 MyInterface 的功能接口。它包含一个名为 getPiValue() 的抽象方法

在主类中,我们声明了对 MyInterface 的引用。注意,我们可以声明接口的引用,但不能实例化接口。就是,

 // it will throw an error
MyInterface ref = new myInterface();

// it is valid
MyInterface ref; 

然后,我们为引用指定了一个lambda表达式。

 ref = () ->.1415; 

最后,我们使用引用接口调用方法 getPiValue()

 System.out.println("Value of Pi = " + ref.getPiValue()); 

带参数的Lambda表达式

到目前为止,我们已经创建了没有任何参数的lambda表达式。但是,与方法类似,lambda表达式也可以有参数。例如《求职面试笔试宝典》

 (n) -> (n%)==0 

这里,括号内的变量n是传递给lambda表达式的参数。lambda主体接受参数并检查它是偶数还是奇数。

示例4:使用带参数的lambda表达式

 @FunctionalInterface
interface MyInterface {

    // abstract method
    String reverse(String n);
}

public class Main {

    public static void main( String[] args ) {

        // declare a reference to MyInterface
        // assign a lambda expression to the reference
        MyInterface ref = (str) -> {

            String result = "";
            for (int i = str.length()-; i >= 0 ; i--)
            result += str.charAt(i);
            return result;
        };

        // call the method of the interface
        System.out.println("Lambda reversed = " + ref.reverse("Lambda"));
    }

} 

输出:

 Lambda reversed = adbmaL 

通用功能接口

到目前为止,我们使用的函数接口只接受一种类型的值。例如

 @FunctionalInterface
interface MyInterface {
    String reverseString(String n);
} 

上面的函数接口只接受字符串并返回字符串。但是,我们可以使函数接口通用,以便接受任何数据类型。如果您不确定泛型,请访问Java泛型。

示例5:通用函数接口和Lambda表达式

 //  Generic Interface.java
@FunctionalInterface
interface GenericInterface<T> {

    // generic method
    T func(T t);
}

// GenericLambda.java
public class Main {

    public static void main( String[] args ) {

        // declare a reference to GenericInterface
        // the GenericInterface operates on String data
        // assign a lambda expression to it
        GenericInterface<String> reverse = (str) -> {

            String result = "";
            for (int i = str.length()-; i >= 0 ; i--)
            result += str.charAt(i);
            return result;
        };

        System.out.println("Lambda reversed = " + reverse.func("Lambda"));

        // declare another reference to GenericInterface
        // the GenericInterface operates on Integer data
        // assign a lambda expression to it
        GenericInterface<Integer> factorial = (n) -> {

            int result =;
            for (int i =; i <= n; i++)
            result = i * result;
            return result;
        };

        System.out.println("factorial of = " + factorial.func(5));
    }
} 

输出:

 Lambda reversed = adbmaL
factorial of = 120 

在上面的示例中,我们创建了一个名为 GenericInterface 的通用函数接口。它包含一个名为 func() 的泛型方法。

在这里,在主类中,

  • GenericInterface<String>reverse- 创建对接口的引用。该接口现在对字符串类型的数据进行操作。
  • GenericInterface<Integer>factorial- 创建对接口的引用。在本例中,接口对整型数据进行操作。

Lambda表达式和StreamAPI

新的 java.util.stream 包已添加到JDK8中,它允许java开发人员执行搜索、筛选、映射、减少或操作列表等集合。

例如,我们有一个数据流(在本例中是一个字符串列表),其中每个字符串都是国家名称和国家地点的组合。现在,我们可以处理这些数据流,只从 尼泊尔 检索地方。

为此,我们可以通过stream API和Lambda表达式的组合在stream中执行批量操作。

示例6:演示将lambdas与stream API一起使用

 import java.util.ArrayList;
import java.util.List;

public class StreamMain {

    // create an object of list using ArrayList
    static List<String> places = new ArrayList<>();

    // preparing our data
    public static List getPlaces(){

        // add places and country to the list
        places.add(" NEPAL , Kathmandu");
        places.add("Nepal,  Pokhara ");
        places.add("India, Delhi");
        places.add("USA, New York");
        places.add("Africa, Nigeria");

        return places;
    }

    public static void main( String[] args ) {

        List<String> myPlaces = getPlaces();
        System.out.println("Places from Nepal:");
        
        // Filter places from Nepal
        myPlaces.stream()
                .filter((p) -> p.startsWith("Nepal"))
                .map((p) -> p.toUpperCase())
                .sorted()
                . forEach ((p) -> System.out.println(p));
    }

} 

输出:

 Places from Nepal:
NEPAL, KATHMANDU
NEPAL, POKHARA 

在上面的示例中,请注意以下语句:

 myPlaces.stream()
        .filter((p) -> p.startsWith("Nepal"))
        .map((p) -> p.toUpperCase())
        .sorted()
        .forEach((p) -> System.out.println(p)); 

这里,我们使用流 API的filter() map() forEach() 等方法。这些方法可以将lambda表达式作为输入。

我们还可以根据上面学习的语法定义自己的表达式。这使我们能够像上面的示例中所看到的那样,大幅减少代码行。

《求职面试笔试宝典》需要的小伙伴私聊我哦~