• lambda表达式


    概述

      lambda表达式是JDK 1.8提供的一种新特性,它使得Java也能像C#和C++语言一样进行简单的“函数式编程”,这不仅简化了某些通用结构的实现方式,也大大增强了Java语言的表达功能。

      lambda表达式是基于数学中的λ演算得名,本质上就是一个没有方法名的匿名方法。

    lambda表达式的使用

      lambda表达式不是独立执行的,而是经常被应用在函数式接口(functional interface)定义的抽象方法的实现中。

    函数式接口

      函数式接口是指只包含一个抽象方法的接口。函数式接口的抽象方法指明了接口的目标用途。

      定义了函数式接口之后,就可以把lambda表达式赋值给该接口的一个引用,lambda表达式定义了函数式接口声明的抽象方法的行为。

      例如:定义一个接口Computer,其中只有一个抽象方法compute(),则Computer是一个函数式接口。

    1 interface Computer {
    2 
    3     int compute(int x, int y);
    4 
    5 }
    Computer

    lambda表达式格式

      lambda表达式类似于匿名内部类,表达式本身实现了函数式接口的唯一抽象方法,而表达式返回的结果是一个函数式接口类型。

      lambda表达式通常以“(参数) -> {方法体}”这样的格式书写,其中“->”被称为lambda运算符或箭头运算符,具体有2种形式:

      省略参数类型:(参数1, 参数2, ...) -> {方法体}

      指定参数类型:(类型1 参数1, 类型2 参数2, ...) -> {方法体}

      如果方法体内只有一个语句,且该语句的返回值类型与抽象方法定义的返回值类型相同,则可以省略“{ }”和return关键字。

     1 @Test
     2 void testLambda() {
     3     Computer add = (x, y) -> x + y;
     4     /***********************************
     5     等同于:
     6     Computer add = new Computer() {
     7 
     8         @Override
     9         public int compute(int x, int y) {
    10             return x + y;
    11         }
    12 
    13     };
    14      ***********************************/
    15 }
    testLambda

      需要注意的是,如果方法体内只有一个语句,而该语句的返回值类型与抽象方法定义的返回值类型不同,则不能省略“{ }”和return关键字。

      如果将compute()方法返回值类型改为void,则上面的代码会报错,提示void类型方法不能返回一个值。

      如果方法体内有多个语句,则需要使用“{ }”括起来。

     1 @Test
     2 void testLambda() {
     3     Computer add = (x, y) -> {
     4         int result = x + y;
     5         return result;
     6     };
     7     /***********************************
     8     等同于:
     9     Computer add = new Computer() {
    10 
    11         @Override
    12         public int compute(int x, int y) {
    13             int result = x + y;
    14             return result;
    15         }
    16 
    17     };
    18      ***********************************/
    19 }
    testLambda 

    示例

      传统用法:

     1 @Test
     2 void testTraditional() {
     3     Computer add = new Computer() {
     4 
     5         @Override
     6         public int compute(int x, int y) {
     7             return x + y;
     8         }
     9 
    10     };
    11     System.out.println("加法计算器:");
    12     System.out.println("90+15=" + add.compute(90, 15));
    13 }
    testTraditional

      lambda表达式用法:

    1 @Test
    2 void testLambda() {
    3     Computer add = (x, y) -> x + y;
    4     System.out.println("加法计算器:");
    5     System.out.println("90+15=" + add.compute(90, 15));
    6 }
    testLambda

      输出结果:

      

    方法引用

      方法引用是lambda表达式的另一种更为简洁的用法。需要注意的是,引用的方法是当前类可以访问到的方法。方法引用分为3种形式:

    类方法的方法引用

      类方法的方法引用的格式为:引用类的类名 :: 引用类的类方法名。该方式需要抽象方法的参数与引用的类方法的参数一致,返回值类型也要一致。

      定义一个Computer函数式接口,该接口中有一个抽象方法compute()。

    1 interface Computer {
    2 
    3     int compute(int x, int y);
    4 
    5 }
    Computer

      定义一个ComputerImpl类,该类中有一个类方法add()。

    1 class ComputerImpl {
    2 
    3     static int add(int x, int y) {
    4         return x + y;
    5     }
    6 
    7 }
    ComputerImpl

      类方法的方法引用。

    1 @Test
    2 void testMethodReferences() {
    3     Computer add = ComputerImpl :: add;
    4 }
    testMethodReferences

    实例方法的方法引用

      实例方法的方法引用有两种格式:

    通过实例引用实例方法

      通过实例引用实例方法的格式为:引用类的类实例 :: 引用类的实例方法名。该方式需要抽象方法的参数与引用的实例方法的参数一致,返回值类型也要一致。

      定义一个Computer函数式接口,该接口中有一个抽象方法compute()。

    1 interface Computer {
    2 
    3     float compute(int x, int y);
    4 
    5 }
    Computer

      定义一个ComputerImpl类,该类中有一个实例变量f和一个实例方法divide()。

    1 class ComputerImpl {
    2 
    3     float f;
    4 
    5     float divide(int x, int y) {
    6         return x / y * f;
    7     }
    8 
    9 }
    ComputerImpl

      通过实例引用实例方法的方法引用。

    1 @Test
    2 void testMethodReferences() {
    3     ComputerImpl computerImpl = new ComputerImpl();
    4     computerImpl.f = 1.0f;
    5     Computer divide = computerImpl :: divide;
    6 }
    testMethodReferences

    通过类名引用实例方法

      通过类名引用实例方法的格式为:引用类的类名 :: 引用类的实例方法名。该方式需要抽象方法的第一个参数为引用类实例,之后的参数与引用的实例方法的参数一致,返回值类型也要一致。注意引用类实例参数必须是抽象方法的第一个参数,不能放在其他位置。

      定义一个Computer函数式接口,该接口中有一个抽象方法compute()。

    1 interface Computer {
    2 
    3     float compute(ComputerImpl computer, int x, int y);
    4 
    5 }
    Computer

      定义一个ComputerImpl类,该类中有一个实例变量f和一个实例方法divide()。

    1 class ComputerImpl {
    2 
    3     float f;
    4 
    5     float divide(int x, int y) {
    6         return x / y * f;
    7     }
    8 
    9 }
    ComputerImpl

      通过类名引用实例方法的方法引用。

    1 @Test
    2 void testMethodReferences() {
    3     Computer divide = ComputerImpl :: divide;
    4 }
    testMethodReferences

    两种方式的区别

      通过实例引用实例方法是先创建一个实例,然后通过实例引用实例方法。当实例改变时,需要再次引用实例方法。

      通过类名引用实例方法是直接通过类名引用实例方法。这种方式引用实例方法需要抽象方法的第一个参数为引用类的实例。当实例改变时,只需在调用方法时传入新的实例即可,无需再次引用实例方法。

    构造方法的方法引用

      构造方法的方法引用的格式为:引用类的类名 :: new。该方式需要抽象方法的参数与构造方法的参数一致,返回值类型为引用类的类型。

      定义一个Computer函数式接口,该接口中有一个抽象方法newInstance()。

    1 interface Computer {
    2 
    3     ComputerImpl newInstance(int x, int y);
    4 
    5 }
    Computer

      定义一个ComputerImpl类,该类中有两个实例变量x和y,以及一个带参构造方法。

     1 class ComputerImpl {
     2 
     3     int x;
     4     int y;
     5 
     6     public ComputerImpl(int x, int y) {
     7         this.x = x;
     8         this.y = y;
     9     }
    10 
    11 }
    ComputerImpl

      构造方法的方法引用。

    1 @Test
    2 void testMethodReferences() {
    3     Computer computer = ComputerImpl :: new;
    4 }
    testMethodReferences
  • 相关阅读:
    GO make&new区别
    GO 包相关
    GO 类型断言
    栈 队列 链表
    表达式求值
    动态规划 最长子序列
    04 单例模式
    02 简单工厂模式
    java设计模式 01 开山篇
    java基础07 多线程
  • 原文地址:https://www.cnblogs.com/lqkStudy/p/11031940.html
Copyright © 2020-2023  润新知