Lambda表达式

Lambda表达式

lambda表达式支持代码块作为参数,lambda表达式允许使用更简洁的代码创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例

1 lambda表达式入门

下面先使用匿名内部类来改写前面介绍的command表达式的例子

package base;

import 命令模式.Command;
import 命令模式.ProcessArray;

public class CommandTest {
    public static void main(String[] args) {
        ProcessArray pa = new ProcessArray();
        int[] target={3,-4,6,4};
        //处理数组,具体处理行为,取决于匿名内部类
        pa.process(target, new Command() {
            @Override
            public void process(int[] target) {
                int sum=0;
                for(int tmp:target){
                    sum+=tmp;
                }
                System.out.println("数组元素总和:"+sum);
            }
        });
    }
}

lambda表达式完全可以于简化创建匿名内部类对象,因此可以将上面代码改为如下形式:

package base;

import 命令模式.ProcessArray;

public class CommandTest2 {
    public static void main(String[] args) {
        ProcessArray pa = new ProcessArray();
        int[] array={3,-4,6,4};
        //处理数组,具体行为取决于匿名内部类
        pa.process(array,(int[] target)->{
            int sum=0;
            for(int tmp:array){
                sum+=tmp;
            }
            System.out.println("array数组的总和:"+sum);
        });
    }
}

从上面的语法格式可以看出,lambda表达式的主要作用就是代替匿名内部类的繁琐的语法,它由三部分组成:

​ 1 形参列表。形参列表允许省略形参类型。如果形参列表中只有一个形参,甚至连形参列表的原括号也可以省略

​ 2 箭头(->)。必须由英文划线号和大于号组成。

​ 3 代码块。如果代码块只包含一条语句。lambda表达式允许省略代码块的花括号,那么这条语句就不要用花括号表示语句结束。lambda表达式代码块只有一条return语句,甚至可以省略return关键字。lambda表达式需要返回值,而它的代码块仅有一条省略了return的语句,lambda表达式会自动返回这条语句的值。

下面示范了几种lambda表达式的简化写法;

package base;
interface Eatable{
    void taste();
}
interface Flyable{
    void fly(String weather);
}
interface Addable{
    int add(int a,int b);
}
public class LambdaQs {
    //调用该方法需要Eatable对象
    public void eat(Eatable e){
        System.out.println(e);
        e.taste();
    }
    //调用该方法需要Flyable对象
    public void drive(Flyable f){
        System.out.println("我正在驾驶:"+f);
        f.fly("碧空如洗的晴日");
    }
    //调用该方法需要Addable对象
    public void test(Addable add)
    {
        System.out.println("5与3的和为:"+add.add(5,3));
    }

    public static void main(String[] args) {
        LambdaQs lq= new LambdaQs();
        //lambda表达式代码块只有一条语句,可以省略花括号
        lq.eat(()-> System.out.println("苹果的味道不错"));
        //lambda表达式的形参列表只有一个形参,可以省略花括号
        lq.drive(weather->{
            System.out.println("今天天气是:"+weather);
            System.out.println("直升机飞行平稳");
        });
        //lambda表达式的代码块只有一条语句,可以省略花括号
        //代码块中只有一条语句,即使该表达式需要返回值,也可以省略return关键字
        lq.test((a,b)->a+b);
    }
}

2 Lambda表达式与函数式接口

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

如果采用匿名内部类来创建函数式接口的实例,则只需实现一个抽象方法,在这种情况下即可采用Lambda表达式来创建对象,该表达式创建出来的对象的目标类型就是这个函数式接口。

Runnable r=()->{
    for(int i=0;i<100;i++){
        System.out.println();
    }
}

Lambda表达式实现的是匿名的方法–因此只能实现一个特定的函数式接口中唯一的方法。这意味着Lambda 表达式有两种限制

1 Lambda表达式只能为函数式接口创建对象,lambda表达式只能实现一个方法,因此他只能有一个抽象方法的接口(函数式接口创建对象)。

2 Lambda表达式的目标类型必须是明确的函数式接口。

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

  • 将lambda表达式赋值给函数式接口类型变量
  • 将lambda表达式作为函数式接口类型的参数传给某个方法
  • 使用函数式接口对lambda表达式进行强制类型转换
Object obj1=(Runnable)->{
    for(int i=0;i<100;i++){
        System.out.println();
    }
}

java8 4种典型的接口

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

XxxConsummer:这类接口中通常包含一个accept()抽象方法。该方法与XxxFunction接口中的方法基本相似,只是该方法不会返回处理结果。

XxxPredicate:这类接口中通常包含一个test()抽象方法,该方法通常用来对参数进行某种判断,然后返回一个boolean值。

XxxSupplier:这个接口中常常包含一个getAsXxx()抽象方法,该方法不需要输入参数,该方法会按照某种逻辑算法返回一个数据。

Lambda表达式与匿名内部类的联系和区别

相同点:

  • lambda表达式和匿名内部类一样,都可以 直接访问“effextively final”的局部变量,以及外部类的成员变量

  • lambda表达式创建的对象与匿名内部类生成的对象一样,都可以直接调用从接口中继承的默认方法

    package base;
    
    interface  Displayable{
        //定义一个抽象方法和默认方法
        void display();
        default int add(int a,int b){
            return a+b;
        }
    }
    public class LambdaAndInner {
        private int age=12;
        private static String name="疯狂软件教育中心";
        public void test(){
            String book="疯狂java 讲义";
            Displayable dis=()->{
                //访问局部变量
                System.out.println("book局部变量为:"+book);
                //访问外部类实例变量和类变量
                System.out.println("外部类age实例变量:"+age);
                System.out.println("外部类的name类变量:"+name);
            };
            dis.display();
            //调用dis对象从接口中继承add默认方法
            System.out.println(dis.add(3,5));
        }
    
        public static void main(String[] args) {
            LambdaAndInner lambda = new LambdaAndInner();
            lambda.test();
        }
    }
    
    

    lammbda表达式与匿名内部类的区别:

    • 匿名内部类可以为任意接口创建实例——不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方法即可;但lambda表达式只能为函数式接口创建实例;
    • 匿名内部类可以为抽象类甚至普通类创建实例;但lambda表达式只能为函数式接口创建实例
    • 匿名内部类实现的抽象方法的方法体允许调用接口定义的默认方法,但lambda表达式的代码块不允许。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值