栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java8新特性(lambda表达式)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java8新特性(lambda表达式)

1.1 lambda表达式简介

理解lambda表达式的Java实现,有两个结构十分关键:第一个是lambda表达式自身,第二个是函数式接口。
lambda表达式本质上就是一个匿名(即未命名)方法。但是,这个方法不是独立执行的,而是用于实现由函数式接口定义的另一个方法。因此,lambda表达式会产生一个匿名类。lambda表达式也常被称为闭包。
函数式接口是仅包含一个抽象方法的接口。这个方法指明了接口的目标用途。因此,函数式接口通常表示单个动作。例如:标准接口Runnable是一个函数式接口,因为它只定义了一个方法run(),run()定义了Runnable的动作。此外,接口式函数定义了lambda表达式的目标类型。特别注意:lambda表达式只能用于其目标类型已被指定的上下文中。

1.1.1 lambda表达式的基础知识

lambda表达式在Java语言中引入了一个新的语法元素和操作符。这个操作符是-> ,操作符被称为lambda操作符或者是箭头操作符。它将lambda表达式分成两个部分,左侧指定了lambda表达式需要的所有参数(如果不需要参数,则使用空的参数列表“()”),右侧指定了lambda体,即lambda表达式要执行的动作。
Java定义了两种lambda体:一种包含单独一个表达式,另一种包含一个代码块。
看一个简单的lambda表达式的例子,它的计算结果是一个常量值,如下所示:

() -> 123.45

这个lambda表达式没有参数,所以参数列表为空,它返回常量值123.45。因此,这个表达式的作用类似于下面的方法;

    double myMath(){
        return 123.45;
    }

lambda表达式定义的方法没有名称
下面在看一个lambda表达式:

() -> Math.random() * 100

这个lambda表达式使用Math.random()获得一个随机数,将其乘以100,然后返回结果。这个lambda表达式也不需要参数。
当lambda表达式需要参数时,需要在操作符左侧的参数列表中加以指定,下面是一个简单的例子:

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

如果参数n的值是偶数,这个lambda表达式会返回true。尽管可以显式指定参数的类型,例如本例中的n,但是通常不需要这么做,因为很多时候,参数的类型是可以从上下文中推断出来。与命名方法一样,lambda表达式可以指定需要用到的任意数量的参数。

1.1.2 函数式接口

函数式接口是仅指定了一个抽象方法的接口。从JDK8开始,可以为接口声明的方法指定默认行为(默认的方法实现),即所谓的默认方法,只有当没有指定默认实现时,接口的方法才是抽象方法。因为没有指定默认实现的接口方法隐式的是抽象方法,所以没有必要使用abstract修饰符。
下面是函数式接口的一个例子:

public interface MyNumber {
    double getValue();
}

在本例中,getValue()方法隐式的是抽象方法,并且是MyNumber定义的唯一方法,所以MyNumber是一个函数式接口,其功能由getValue()定义。
lambda表达式不是独立执行的,而是构成了一个函数式接口定义的抽象方法的实现,该函数式接口定义了它的目标类型,只有在定义了lambda表达式的目标类型的上下文中,才能使用该表达式。当把一个lambda表达式赋给一个函数式接口引用时,就创建了这样的上下文。
下面通过一个例子来说明如何在参数上下文中使用lambda表达式。首先,声明对函数式接口MyNumber的一个引用

MyNumber myNum;

接下来,将一个lambda表达式赋给该接口引用:

myNum = () -> 123.45;

当目标类型上下文中出现lambda表达式时,会自动创建实现了函数式接口的一个类的实例,函数式接口声明的抽象方法的行为由lambda表达式定义。当通过目标调用该方法时,就会执行lambda表达式。因此,lambda表达式提供了一种将代码片段转换为对象的方法
在前面的例子中,lambda表达式成了getValue()方法的实现,所以,下面的代码将显示123.45:

System.out.println(myNum.getValue());
//结果如下:
//123.45

因为赋给myNum的lambda表达式返回值为123.45,所以调用getValue()方法返回的值也是123.45
为了在目标类型上下文中使用lambda表达式,抽象方法的类型和lambda表达式的类型必须兼容。例如:如果抽象方法指定了两个int类型的参数,那么lambda表达式也必须指定两个参数,其类型要么被显式的指定为int类型,要么在上下文中可以隐式的推断为int类型。总的来说,lambda表达式的参数类型和数量必须与方法的参数兼容;返回类型必须兼容;并且lambda表达式可能抛出的异常必须能被方法接受

package lambda;

interface NumericTest{
    boolean test(int n);
}

public class LambdaDemo2 {
    public static void main(String[] args) {
        NumericTest isEven = (n) -> (n % 2) == 0;
        if (isEven.test(10)){
            System.out.println("10 是偶数");
        }
        if (!isEven.test(9)){
            System.out.println("9不是偶数");
        }
        NumericTest isNonNeg = (n) -> n >= 0;
        if (isNonNeg.test(1)){
            System.out.println("1是正数");
        }
        if (!isNonNeg.test(-1)){
            System.out.println("-1不是正数");
        }
    }
}
//结果:
//10 是偶数
//9不是偶数
//1是正数
//-1不是正数

这个程序演示了关于lambda表达式的一个重要的地方:函数式接口引用可以用来执行任何与其兼容的lambda表达式。注意,程序中定义了两个不同的lambda表达式,它们都是与函数式接口NumericTest的test()方法兼容,所以都可以通过NumericTest引用执行。
当lambda表达式中有多个参数时,如下所示:

(n,d) -> (n % d) == 0;

两个参数n和d才参数列表中指定,并且用逗号隔开。每当需要一个以上的参数时,就在lambda表达式操作符左侧,使用一个带括号的参数列表指定参数,参数之间使用逗号隔开。
对于lambda表达式中的多个参数,有一点十分重要:如果需要显式声明一个参数类型,那么必须为所有的参数声明类型。例如下面的代码是合法的:

(int n,int d) -> (n % d) == 0;

这是不合法的:

(int n, d) -> (n % d) == 0;
1.2 块lambda表达式

块lambda表达式是操作符的右侧的代码不是一个简单的表达式,而是由一个代码块组成,其中包含多条语句。这种类型的lambda体被称为块体,具有块体的lambda表达式被称为块lambda。
块lambda扩展了lambda表达式内部可以处理的操作类型,因为它允许lambda体包含多条语句。例如,在块lambda中可以声明变量、使用循环、指定if和switch语句、创建嵌套代码块等。创建块lambda只需要使用花括号包围lambda体,就像创建其他语句块一样。
在块lambda中重要一点是:在块lambda中必须显式使用return语句来返回值。因为块lambda体代表的不是单独一个表达式。
下面这个例子使用块lambda来计算并返回一个int类型值的阶乘:

package lambda;

interface NumuricFunc{
    int func(int n);
}

public class BlockLambdaDemo {
    public static void main(String[] args) {
        NumuricFunc factorial = (n) -> {
          int result = 1;
          for (int i = 1;i <= n;i++){
              result *= i;
          }
          return result;
        };
        System.out.println(factorial.func(3));
        System.out.println(factorial.func(6));
    }
}
//结果如下:
//6
//720

在程序中,块lambda声明了变量result,使用了for循环,有一条return语句。在lambda表达式中出现return语句时,只是从lambda体返回,而不会导致包围lambda提的方法返回

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/346099.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号