84-Java Lambda 表达式
Java Lambda 表达式在本文中我们将通过示例了解Java lambda表达式以及lambda表达式与函数接口、泛型函数接口和流API的使用。lambda表达式是在Java 8中首次引入的。其主要目的是提高语言的表达能力。但是在学习lambda之前我们首先需要了解功能接口。什么是功能接口如果Java接口仅包含一个抽象方法则将其称为功能接口。仅这一种方法指定了接口的预期用途。例如包java.lang中的Runnable接口;是一个功能接口因为它只组成一个方法即run()。示例1在java中定义功能接口import java.lang.FunctionalInterface; FunctionalInterface public interface MyInterface{ //单一抽象方法 double getValue(); }在上面的示例中接口MyInterface只有一个抽象方法getValue()。因此它是一个功能接口。在这里我们使用了注解FunctionalInterface。该注解会强制Java编译器指示该接口是功能接口。因此不允许有多个抽象方法。但是它不是强制性的。在Java 7中功能接口被视为单一抽象方法(SAM)类型。在Java 7中SAM类型通常是通过匿名类实现的。示例2使用Java中的匿名类实现SAM示例public class FunctionInterfaceTest { public static void main(String[] args) { //匿名类 new Thread(new Runnable() { Override public void run() { System.out.println(我刚刚实现了Runnable功能接口。); } }).start(); } }输出我刚刚实现了Runnable功能接口。在这里我们可以将匿名类传递给方法。这有助于用Java 7编写代码更少的程序。但是语法仍然很困难需要大量的额外代码行。Java 8进一步扩展了SAM的功能。由于我们知道功能接口只有一个方法因此在将其作为参数传递时无需定义该方法的名称。Lambda表达式使我们能够做到这一点。Lambda表达式简介Lambda表达式本质上是一个匿名或未命名的方法。lambda表达式不能单独执行。相反它用于实现功能接口定义的方法。如何在Java中定义Lambda表达式这是我们如何在Java中定义lambda表达式。(parameter list) - lambda body使用的新运算符-被称为箭头运算符或lambda运算符。让我们探索一些实例假设我们有一个这样的方法double getPiValue() { return 3.1415; }我们可以使用lambda表达式编写此方法如下所示() - 3.1415在此该方法没有任何参数。因此运算符的左侧包括一个空参数。右侧是lambda主体用于指定lambda表达式的操作。在这种情况下它将返回值3.1415。Lambda 主体的类型在Java中lambda主体有两种类型。1.单个表达式主体() - System.out.println(Lambdas are great);这种类型的lambda主体称为表达式主体。2.由代码块组成的主体。() - { double pi 3.1415; return pi; };这种类型的lambda体称为块体。块主体允许lambda主体包含多个语句。这些语句包含在括号内您必须在括号后添加分号。注意对于块体您应该始终有一个return语句。但是单个表达式主体不需要return语句。示例3Lambda表达式让我们编写一个Java程序该程序使用lambda表达式返回Pi的值。如前所述lambda表达式不是单独执行的。相反它形成了由功能接口定义的抽象方法的实现。因此我们需要首先定义一个功能接口。示例import java.lang.FunctionalInterface; //这是功能接口 FunctionalInterface interface MyInterface{ // 抽象方法 double getPiValue(); } public class Main { public static void main( String[] args ) { //声明对MyInterface的引用 MyInterface ref; // lambda 表达式 ref () - 3.1415; System.out.println(Pi ref.getPiValue()); } }输出Pi 3.1415在以上示例中我们创建了一个名为MyInterface的功能接口。它包含一个名为getPiValue()的抽象方法在Main类内部我们声明了对MyInterface的引用。请注意我们可以声明接口的引用但不能实例化接口。那是因为//它将抛出一个错误 MyInterface ref new myInterface(); // 这是有效的 MyInterface ref;然后我们为引用分配了一个lambda表达式。ref () - 3.1415;最后我们使用reference接口调用方法getPiValue()。System.out.println(Pi ref.getPiValue());带参数的Lambda表达式到现在为止我们已经创建了不带任何参数的lambda表达式。但是类似于方法lambda表达式也可以具有参数。例如(n) - (n%2)0在此括号内的变量n是传递给lambda表达式的参数。Lambda主体接受参数并检查其是偶数还是奇数。示例4将lambda表达式与参数一起使用示例FunctionalInterface interface MyInterface { //抽象方法 String reverse(String n); } public class Main { public static void main( String[] args ) { //声明对MyInterface的引用 //将lambda表达式分配给引用 MyInterface ref (str) - { String result ; for (int i str.length()-1; i 0 ; i--){ result str.charAt(i); } return result; }; //调用接口的方法 System.out.println(Lambda reversed ref.reverse(Lambda)); } }输出Lambda reversed adbmaL泛型功能接口到目前为止我们已经使用了仅接受一种类型的值的功能接口。例如FunctionalInterface interface MyInterface { String reverseString(String n); }上面的功能接口仅接受String并返回String。但是我们可以使功能接口通用以便接受任何数据类型。示例5泛型功能接口和Lambda表达式示例// GenericInterface.java FunctionalInterface interface GenericInterfaceT { // 泛型方法 T func(T t); } // GenericLambda.java public class Main { public static void main( String[] args ) { //声明对GenericInterface的引用 // GenericInterface对String数据进行操作 //为其分配一个lambda表达式 GenericInterfaceString reverse (str) - { String result ; for (int i str.length()-1; i 0 ; i--) result str.charAt(i); return result; }; System.out.println(Lambda reversed reverse.func(Lambda)); //声明对GenericInterface的另一个引用 // GenericInterface对整数数据进行操作 //为其分配一个lambda表达式 GenericInterfaceInteger factorial (n) - { int result 1; for (int i 1; i n; i) result i * result; return result; }; System.out.println(5的阶乘 factorial.func(5)); } }输出Lambda reversed adbmaL 5的阶乘 120在上面的示例中我们创建了一个名为GenericInterface的泛型功能接口。它包含一个名为func()的泛型方法。在类内部GenericInterfaceString reverse - 创建对该接口的引用。 现在该接口可以处理String类型的数据。GenericInterfaceInteger factorial -创建对该接口的引用。 在这种情况下该接口对Integer类型的数据进行操作。Lambda表达式和流API新的 java.util.stream 包已添加到 JDK8 中它允许java开发人员执行搜索、过滤、映射、减少等操作或者操作列表等集合。例如我们有一个数据流在我们的示例中是一个字符串列表其中每个字符串都是国家名称和国家/地区的组合。 现在我们可以处理此数据流并且仅从Nepal检索位置。为此我们可以结合使用Stream API和Lambda表达式在流中执行批量操作。示例6演示将lambda与Stream API一起使用示例import java.util.ArrayList; import java.util.List; public class StreamMain { //使用ArrayList创建一个列表对象 static ListString places new ArrayList(); //准备我们的数据 public static List getPlaces(){ //将地点和国家添加到列表中 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 ) { ListString myPlaces getPlaces(); System.out.println(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));在这里我们使用的是Stream API的filter()map()和forEach()之类的方法。 这些方法可以将lambda表达式作为输入。我们还可以根据上面学习的语法定义自己的表达式。如上例所示这使我们可以大大减少代码行。 福利时间如果你正在备战面试或者想要学习其他知识给大家推荐一个宝藏知识库作者整理了一些列 Java 程序员需要掌握的核心知识有需要的自取不谢。知识库地址https://farerboy.com/