Java8新增的Lambda表达式

一.Lambda表达式入门

Lambda表达式支持将代码块作为方法参数,允许使用更简洁的代码来创建只有一个抽象方法的接口(函数式接口)的实例。
Lambda表达式的语法分为三部分:
· 形参列表:形参列表允许省略形参类型,如果形参列表中只有一个参数,甚至连形参列表的圆括号也可以省略。
· 箭头(->):左侧是形参列表,右侧花括号内的内容是代码块。
· 代码块:重写的方法的代码。如果代码块中只有一条语句,就可以省略花括号;如果代码块中只有一条return语句,那么连return也可以省去,Lambda语句会自动将结果返回。

/* 
 * 看一段代码,体会一下Lambda表达式的用法
 * /
//定义三个接口
interface Eatting { void food(String foods); }
interface Sleeping { void sleeptight(); }
interface Addable { int adding(int a, int b); }

public class LambdaTest {

    //调用接口
    public void eat(Eatting e) {
        e.food("steak");
    }

    public void sleep(Sleeping s) {
        s.sleeptight();
    }

    public void add(Addable add) {
        System.out.println("2+3 = " + add.adding(2,3));
    }

    public static void main(String[] args) {
        LambdaTest lt = new LambdaTest();

        //通过实例的方法,使用Lambda表达式创建方法中需要的接口类型实例
        //省略形参列表的圆括号和代码块的花括号
        lt.eat(foods ->  System.out.println(foods + " is tasty!") );

        //形参列表中没有参数时,不能省略圆括号;省略代码块的花括号
        lt.sleep(() -> System.out.println("sleeptight is pretty good!") );

        //返回值为a、b之和,省略了return
        lt.add((a,b) -> a+b );
    }
}

二.Lambda表达式与函数式接口

Lambda表达式的类型是目标类型(target type),目标类型必须为函数式接口。函数式接口是有且只有一个抽象方法,无论有几个变量、默认方法或类方法,但抽象方法只能有一个的一种接口。查看Java8的API文档中会发现有很多函数式接口,比如我们多线程常用的Runnable接口就是一个函数式接口

/*
 * Runnable只包含一个无参数的抽象函数run();
 * Lambda表达式的返回值赋给了Runnable的一个对象
 */
Runnable r = () -> {
    for(int i = 0;i < 100;i++)
        System.out.println(i + " ");
};

从上面代码可以看到Lambda表达式的结果(即目标类型)被当做对象,可以将其直接进行赋值操作

/* 
 * 因为赋给了Object类型,不是函数式接口,所以这段代码不能够编译运行
 */
Objective obj = () -> {
    for(int i = 0;i < 100;i++)
        System.out.println(i + " ");
};

/* 
 * 但将其强制类型转换之后就可以赋给Object类型
 */
 Objective obj = (Runnable)() -> {
    for(int i = 0;i < 100;i++)
        System.out.println(i + " ");
};

通过以上代码我们发现,Lambda表达式类型必须是明确的函数式接口,并且可以为函数式接口创建对象。为保证目标类型是一个明确的目标类型可以通过三种方式:
· 将目标类型直接赋值给函数式接口的对象
· 将目标类型作为某个函数的参数
· 将目标类型进行强制类型转换
Java8在java.util.function包下预定义了大量函数式接口,想深入了解的同学可以查看API文档学习

三.方法引用于构造器引用

方法构造和构造器引用都需要使用两个英文冒号,所谓引用是在代码块即在花括号中的代码引用了方法或构造器,分为四种引用类型:
1. 引用类方法:
- 示例:类名:类方法
- 说明:函数式接口中被实现的方法的全部参数传给该方法作为参数
- 对应的Lambda表达式:(a,b,…)->类名.类方法(a,b,…)
e.g.:

/*
 * 定义函数式接口,@FunctionalInterface注解对程序没有任何功能上的作用,只是在编译上严格保证这是一个函数式接口,是Java8新增的注解。
@FunctionalInterface
public interface Converter {
    Integer converter(String from);
}
//使用Lambda表达式创建函数式接口对象
//普通方式
Converter converter1 = from -> Integer.valueOf(from);
//因为valueOf是Integer类的静态方法,可以直接使用类名::类方法的方式创建函数式接口对象
Converter converter2 = Integer::valueOf;

Integer value1 = converter1.converter("99");
Integer value2 = converter2.converter("100");

System.out.println(value1 + " --- " + value2);

输出结果:99 --- 100
2. 引用特定对象的实例方法
- 示例:特定对象::实例方法
- 说明:函数式接口中被实现的方法的全部参数传给该方法作为参数
- 对应的Lambda表达式:(a,b,…)->特定对象.实例方法(a,b,…)
e.g.:

//接口使用上面定义的Converter接口
//使用Lambda表达式创建函数式接口对象
//普通方式
Converter converter3 = from -> "ILoveLambda".indexOf(from);
//因为indexOf是String类的实例方法,可以直接使用特定对象::实例方法的方式创建函数式接口对象
Converter converter4 = "ILoveLambda"::indexOf;

Integer value3 = converter3.converter("Lambda");
Integer value4 = converter4.converter("Lambda");

System.out.println(value3 + " --- " + value4);

输出结果:5 --- 5

3. 引用某类对象的实例方法
- 示例:类名::实例方法
- 说明:函数式接口中被实现的方法的第一个参数作为调用者,后面参数全部传给该方法作为参数
- 对应的Lambda表达式:(a,b,…)->a.实例方法(b,…)
e.g.:

//定义接口,sub方法含有三个参数
@FunctionalInterface
public interface Sub {
    String sub(String a, int b, int c);
}
//普通方式创建函数式接口对象
Sub sub1 = (a,b,c) -> a.substring(b, c);
//使用类名::实例方法的方式创建函数式接口对象
Sub sub2 = String::substring;

String value5 = sub1.sub("ILoveLambda", 1, 5);
String value6 = sub2.sub("ILoveLambda", 5, 11);

System.out.println(value5 + " " + value6);

运行结果:Love Lambda

4. 引用构造器
- 示例:类名::实例方法
- 说明:函数式接口中被实现的方法的第一个参数作为调用者,后面参数全部传给该方法作为参数
- 对应的Lambda表达式:(a,b,…)->a.实例方法(b,…)
e.g.:

//定义接口
@FunctionalInterface
public interface gouZao {
    String str(String title);
}
//普通方式创建函数式接口对象
gouZao gz1 = (String a) -> new String(a);
//引用构造器方式创建函数式接口对象
gouZao gz2 = String::new;

String string1 = gz1.str("this is a test of Lambda?");
String string2 = gz2.str("this is a test of Lambda!");

System.out.println(string1 + " - " + string2);

运行结果:this is a test of Lambda? - this is a test of Lambda!

四.Lambda表达式与匿名内部类

可以看出,Lambda表达式的功能与匿名内部类很相似,Lambda表达式就是为了使匿名内部类的代码更简洁,但这种方式只适合于函数式接口才可以使用。
Lambda表达式与匿名内部类的区别如下:
- 匿名内部类可以为任何接口创建实例,也可以为抽象类甚至普通类创建实例;而Lambda表达式只能为函数式接口创建实例
- 匿名内部类实现的抽象方法允许调用接口中定义的默认方法;但Lambd表达式不允许调用接口中的默认方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值