Lambda表达式之方法引用和构造器引用

在这里插入图片描述

Lambda表达式的含义

Lambda省去面向对象的条条框框,格式由3个部分组成:

  • 一些参数
  • 一个箭头
  • 一段代码

Lambda表达式的标准格式为:

(参数类型 参数名称) -> { 代码语句 }

格式说明:

  • ( ):接口中的抽象方法的参数列表,无参数则留空,有参数就写出参数;多个参数则用逗号分隔。
  • -> :是新引入的语法格式,代表指向动作,传递的意思,把小括号内的参数传递给后面的方法体{ }。
  • { }:语法与传统方法体要求基本一致即重写接口的抽象方法的方法体。

Lambda省略格式

可推导即可省略

Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。例如上例还可以使用Lambda的省略写法:

public static void main(String[] args) {
  	invokeCalc(120, 130, (a, b) -> a + b);
}
Lambda省略规则

在Lambda标准格式的基础上,使用省略写法的规则为:

  1. 小括号内参数的类型可以省略;
  2. 如果小括号内有且仅有一个参数,则小括号可以省略;
  3. 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。

注意:要省略 {}return, ;必须一起省略

Lambda表达式与函数式接口

Lambda表达式的类型,也被称为“目标类型(target type)" ,Lambda表达式的目标类型必须是”函数式接口(function interface)"。函数式接口代表只包含一个抽象方法的接口。函数式接口可以包含多个默认方法(default修饰),类方法,但只能声明一个抽象方法。

由于Lambda表达式的结果就是被当成对象,因此程序中完全可以使用Lambda表达式进行赋值,例如如下代码。

// Runnable接口只包含一个无参数的方法
// Lambda表达式代表的匿名方法实现了Runnable接口中唯一的,无参数的方法
// 因此下面的Lambda表达式创建了一个Runnable对象
Runnable r = () -> {
    for (int i = 0; i < 100; i ++) {
        System.out.println();
    }
};

从上面的代码可以看出,Lambda表达式实现的是匿名方法-因此它只能实现特定函数式接口中的唯一方法。这意味着Lambda表达式有如下两个限制:

  • Lambda表达式的目标类型必须是明确的函数式接口
  • Lambda表达式只能为函数式接口创建对象。Lambda表达式只能实现一个方法,因此它只能为只有一个抽象方法的接口(函数式接口)创建对象。
重点:

为保证Lambda表示式的目标类型是一个明确的函数式接口,可以有如下三种常见方式。

  • 将Lambda表示式赋给函数式接口类型的变量
  • 将Lambda表示式作为函数式接口类型的参数传给某个方法
  • 使用函数式接口对Lambda表示式进行强制类型转换
//错误写法:会报不兼容的类型 Object 不是函数式接口
Object obj = () -> {
    for (int i = 0; i < 100; i++) {
        System.out.println();
    }
};
// 正确写法
Object obj = (Runnable) () -> {
    for (int i = 0; i < 100; i++) {
        System.out.println();
    }
};

Java 8在java.util.function包下预定义了大量函数式接口,典型地包含如下4类接口.

XxxFunction:这类接口中通常包含一个apply()抽象方法,该方法对掺数进行处理、转换(apply()
方法的处理逻辑由Lambda表达式来实现),然后返回一个新的值。该函数式接口通常用于对指定数据进行转换处理.

XxxConsumer:这类接口中通常包含一个accept()抽象方法,该方法与XxxFunction接口中的apply()方法基本相似,也负责对參数进行处理,只是该方法不会返回处理结果.

XxxxPredicate,这类接口中通常包含一个test()抽象方法,该方法通常用来对参数进行某种判断
(test()方法的判断逻辑由Lambda表达式来实现),然后返回一个boolean值.该接口通常用于判断参数是否满足特定条件,经常用于进行筛滤数据.

XxxSupplier:这类接口中通常包含一个getAsXxx()抽象方法,该方法不需要输入参数,该方法会按照某种逻辑算法(getAsXxx()方法的逻辑算法由Lambda表达式实现)返回一个数据。

方法引用与构造器引用

如果Lambda表达式的代码块只有一条代码,程序就可以省略Lambda表达式中代码块的花括号。不仅如此,如果Lambda表达式的代码块只有一条代码,还可以在代码块中使用方法引用和构造器引用。

方法引用和构造器引用可以让Lambda表达式的代码块更加简洁。方法引用和构造器引用都需要使用两个英文冒号。

Lambda表达式支持如所示的几种引用方式。

种类示例说明对应的Lambda表达式
引用类方法类名::类方法函数式接口中被实现方法的全部参数传给该类方法作为参数(a,b…) -> 类名.类方法(a,b…)
引用特定对象的实例方法特定对象::实例方法函数式接口中被实现方法的全部参数传给该方法作为参数(a,b,…) -> 特定对象.实例方法(a,b,…)
引用某类对象的实例方法类名::实例方法函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数(a,b,…) -> a.实例方法(b,…)
引用构造器类名::new函数式接口中被实现方法的全部参数传给该构造器作为参数(a,b,…) -> new 类名(a,b,…)
举例说明
@FunctionInterface 
interface Converter {
    Integer convert(String from);
}
  1. 引用方法
Lambda实现: 
Converter converter1 = from -> Integer.valueOf(from);

方法引用实现:
Converter converter1 = Integer::valueOf;

Integer val = converter1.convert("99");
System.out.println(val);  // 99

2.引用特定对象的实例方法

Lambda实现:
Converter converter2 = from -> "helloworld".indexOf(from);

方法引用实现:
Converter converter2 = "helloworld"::indexOf;

Integer value = Converter2.convert("it");
System.out.println(value); // 2

3.引用某类对象的实例方法

@FunctionInterface
interface MyTest {
    String test(String a, int b, int c);
}
Lambda实现:
MyTest mt = (a, b, c) -> a.subString(b, c);

方法引用实现:
Mytest mt = String::subString;

String str = mt.test("Java I Love you", 2, 9);
System.out.println(str);   // va I Lo
  1. 引用构造器
@FunctionInterface
interface YourTest {
    JFrame win(String title);
}
Lambda实现:
YourTest yt = (String a) -> new JFrame(a);

方法引用实现:
YourTest yt = JFrame::new;

JFrame jf = yt.win("我的窗口");
System.out.println(jf);
综合对比
package java_code_exercise;

//                         _ooOoo_  
//                        o8888888o  
//                        88" . "88  
//                        (| -_- |)  
//                         O\ = /O  
//                     ____/`---'\____  
//                   .   ' \\| |// `.  
//                    / \\||| : |||// \  
//                  / _||||| -:- |||||- \  
//                    | | \\\ - /// | |  
//                  | \_| ''\---/'' | |  
//                   \ .-\__ `-` ___/-. /  
//                ___`. .' /--.--\ `. . __  
//             ."" '< `.___\_<|>_/___.' >'"".  
//            | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//              \ \ `-. \_ __\ /__ _/ .-` / /  
//      ======`-.____`-.___\_____/___.-`____.-'======  
//                         `=---='  
//
//      .............................................  
//               佛祖保佑             永无BUG 
//       佛曰:  
//               写字楼里写字间,写字间里程序员;  
//               程序人员写程序,又拿程序换酒钱。  
//               酒醒只在网上坐,酒醉还来网下眠;  
//               酒醉酒醒日复日,网上网下年复年。  
//               但愿老死电脑间,不愿鞠躬老板前;  
//               奔驰宝马贵者趣,公交自行程序员。  
//               别人笑我忒疯癫,我笑自己命太贱;  
//               不见满街漂亮妹,哪个归得程序员? 

/**
 @FunctionalInterface
public interface Converter {
    Integer convert(String from);
}
 */


/**
 * @author swordsmanye
 * @data 2019/9/15 11:04
 */
public class LambdaStream {
    public static void main(String[] args) {
        // 匿名内部类方法实现
        Converter converter = new Converter() {
            @Override
            public Integer convert(String from) {
                return Integer.valueOf(from);
            }
        };
        Integer val = converter.convert("98");
        System.out.println(val);

        // Lambda表达式实现
        Converter converter1 = a -> Integer.valueOf(a);
        Integer val1 = converter1.convert("99");
        System.out.println(val);

        // 方法引用
        Converter converter2 = Integer::valueOf;
        Integer val2 = converter2.convert("100");
        System.out.println(val2);
    }

}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值