Java 8新增的Lambda表达式

参考资料

[1]. 疯狂Java讲义(第三版) 李刚

Lambda表达式

Lambda表达式入门

允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例,先来一个示例:
接口Commond


/**
 * Commond interface
 *
 * @author shuaige
 * @date 2018/01/23
 */
public interface Commond {
    /**
     * 接口里定义的process方法用于封装“处理行为”
     * @param target
     */
    void process(int[] target);
}

使用传入内部类的写法


/**
 * CommandTest class
 *
 * @author shuaige
 * @date 2018/01/25
 */
public class CommandTest {
    public static void main(String[] args)
    {
        ProcessArray pa = new ProcessArray();
        int[] target = {3, -4, 6, 4};
        pa.process(target, new Commond() {
            @Override
            public void process(int[] target) {
                int num = 0;
                for (int tmp : target)
                {
                    num += tmp;
                }
                System.out.println("数组元素的总和是:" + num);
            }
        });

    }
}

使用Lambda表达式改写


/**
 * CommandTest class
 *
 * @author shuaige
 * @date 2018/01/25
 */
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 num = 0;
            for (int tmp : target)
            {
                num += tmp;
            }
            System.out.println("数组元素的总和是:" + num);
        });

    }
}

Lambda表达式的初步应用:
Eatable接口

/**
 * Eatable interface
 *
 * @author shuaige
 * @date 2018/01/25
 */
public interface Eatable {
    void taste();
}

Flyable接口

/**
 * Flyable interface
 *
 * @author shuaige
 * @date 2018/01/25
 */
public interface Flyable {
    void fly(String weather);
}

Addable接口

/**
 * Addable interface
 *
 * @author shuaige
 * @date 2018/01/25
 */
public interface Addable {
    int add(int a, int b);
}

使用示例:


public class LambdaQs {
    /**
     * 调用该方法需要Eatable对象
     * @param e
     */
    public void eat(Eatable e)
    {
        System.out.println(e);
        e.taste();
    }

    /**
     * 调用该方法需要Flyable对象
     * @param f
     */
    public void drive(Flyable f)
    {
        System.out.println("我正在驾驶:" + f);
        f.fly("【碧空如洗的晴日】");
    }

    /**
     * 调用该方法需要Addable对象
     * @param add
     */
    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("苹果的味道不错"));
        lq.drive(weather -> {
            System.out.println("今天的天气是:" + weather);
            System.out.println("直升机飞行平稳");
        });

        /**
         * Lambda表达式只有一条语句,可以省略花括号
         * 代码块中只有一条语句,即使该表达式需要返回值,也可以省略return关键字
         */
        lq.test((a, b) -> a+b);
    }
}

Lambda表达式与函数式接口

将Lambda表达式赋值给函数式接口类型的变量

// Runnable是Java本身提供的一个函数式接口
// Runnable接口中只包含一个无参数的方法
// 因此下面的Lambda创建了一个Runnable对象
Runnable r = () -> {
     System.out.println("输出...");
}

如果把表达式赋值给一个非函数式接口或参数不对应的接口会报错

Object o = () -> {
     System.out.println("输出...");
}

使用函数式接口对Lambda表达式进行强制类型转换

Object o = (Runnable)() -> {
     System.out.println("输出...");
}

Lambda表达式实现的匿名方法与目标类型目标(函数式接口)中唯一的抽象方法有相同的形参列表即可。
首先定义一个接口

@FunctionalInterface
public interface TestInterface{
    void run();
}

再把上面的代码强制转换为这接口

Object o = (TestInterface)() -> {
     System.out.println("输出...");
}

方法引用与构造器引用

简单来说,就是可以在Lambda表达式中直接使用某个类的方法或构造器,不用手动在这里临时写了,很方便。
Converter 接口

/**
 * 函数式接口
 */
@FunctionalInterface
public interface Converter {
    /**
     * 转换字符串为数字
     * @param from
     * @return
     */
    Integer convert(String from);
}

引用类方法

使用Lambda表达式来创建一个Converter 对象

// 自己编写
Converter converter1 = from -> Integer.valueOf(from);
// 引用类Integer类方法的valueOf方法
Converter converter2 = Integer::valueOf;
// 测试
Integer i1 = converter1.convert("99");
Integer i2 = converter2.convert("99");

引用特定对象的实例方法

// 自己编写
Converter converter1 = from -> "www.baidu.com".indexOf(from);
// 引用String类的indexOf实例方法
Converter converter2 = "www.baidu.com"::indexOf;
Integer value1 = converter1.convert("b");
Integer value2 = converter2.convert("b");

引用某类对象的实例方法

函数式接口MyTest

/**
 * 函数式接口,根据String、int、int三个参数生成一个String返回值
 */
@FunctionalInterface
public interface MyTest {
    /**
     * 测试方法
     * @param a
     * @param b
     * @param c
     * @return
     */
    String test(String a, int b, int c);
}

使用示例

// 编写Lambda方法从第某位开始截取到第某位
MyTest mt1 = (a,b,c)-> a.substring(b,c);
String str1 = mt1.test("www.baidu.com", 2, 9);
// 方法引用替代了Lambda表达式:引用某类对象的实例方法
// 函数式接口中被实现方法的第一个参数作为调用者
// 后面的参数全部传给该方法作为参数
MyTest mt2 = String::substring;
String str2 = mt2.test("www.baidu.com", 2, 9);

引用构造器

引用构造器
函数式接口YourTest

/**
 * 函数式接口
 */
@FunctionalInterface
public interface YourTest {
    JFrame win(String title);
}

使用示例:

// 使用Lambda表达式创建YourTest对象
YourTest yt1 = (String a) ->  new JFrame(a);
JFrame jf1 = yt1.win("我的窗口");
// 使用方法的构造器
YourTest yt2 = JFrame::new;
JFrame jf2 = yt1.win("我的窗口");

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

相同点:
1. 都可以直接访问“effectively final”的局部变量,以及外部类的成员变量(包括示例变量和类变量)。
2. 都可以直接调用从接口中继承的默认方法

区别点:
1. 匿名内部类可以为任意接口创建示例,不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方法即可;但Lambda表达式只能为函数式接口创建实例。
2. 匿名内部类可以为抽象类甚至普通类创建实例,但Lambda只能为函数式接口创建实例。
3. 匿名内部类实现的抽象方法的方法体允许调用接口中的默认方法,但Lambda表达式的代码块不允许调用接口中定义的默认方法。

package com.qunar;
/**
 * Lambda表达式与匿名内部类的联系和区别
 */
public class LambdaAndInner {
    private int age = 12;
    private static String name = "百度";
    public void test()
    {
        String book = "一本书";
        Displayable dis = ()->{
            // 访问“effectively final”的局部变量
            System.out.println("book局部变量为:" + book);
            // 访问外部类的实例变量和类变量
            System.out.println("外部类的age实例变量为:" + age);
            System.out.println("外部类的name类变量为:" + name);
            // 下面会报错,无法接口里的其他默认方法
            // System.out.println(add(3, 5));
        };

        dis.display();
        // 调用dis对象从接口中继承的add()方法
        System.out.println(dis.add(3, 5));
    }

    public static void main(String[] args)
    {
        LambdaAndInner lambds = new LambdaAndInner();
        lambds.test();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值