java8特性: lambda表达式语法入门-笔记狂魔

lambda表达式简介

lambda表达式是java8推出的特性之一, 是一颗语法糖, 可以看成是一个匿名内部类的简化版(但是必须基于函数式接口, 后文中有说到), 用于写出更优雅的代码

注: 本篇博客适合于刚学习lambda表达式的小伙伴, 阅读本文需要一点匿名内部类相关知识

入门案例: 将匿名内部类改为lambda表达式进行对比

1. 准备一个接口Animal
public interface Animal {

    // 动物吃东西
    void eat();
}
2. 采用匿名内部类的方式创建对象
public static void main(String[] args) {

	// 创建对象cat
    Animal cat = new Animal() {
        @Override
        public void eat() {
            System.out.println("猫吃老鼠");
        }
    };
    cat.eat();
}
3. 改为lambda的方式创建对象
public static void main(String[] args) {

	// 创建cat对象
    Animal cat = () -> System.out.println("猫吃老鼠");
    cat.eat();
}
4. 对比

可以看到, 在实现相同的功能时, 使用lambda语法可以使得代码异常的简洁

lambda表达式语法说明(案例在后文中给出)

1. 基本语法
  1. 只能当接口是函数式接口时, 才能使用lambda表达式代替匿名内部类的方式创建对象. 函数式接口: 如果一个接口中有且只有一个抽象方法(可以有其他方法比如default方法等, 但是抽象方法只能有一个),则该接口就可以称之为函数式接口
  2. lambda表达式语法中, 方法参数和方法体之间用箭头符号"->"进行连接, 方法参数列表与返回值需要跟接口中的方法保持一致, 这样才能正确识别
// lambda表达式语法
(Object obj1,Object obj2,Object obj3...)->{
    // 方法体
    return;
}
2. 省略模式
  1. 形参列表中的变量类型可以省略, 若是省略一个, 则必须全都省略
// 省略参数类型
(obj1,obj2,obj3...)->{
    // 方法体
    return;
}
  1. 若是只有一个形参, 则可以不写小括号
// 省略小括号
obj1->{
    // 方法体
    return;
}
  1. 若代码块中只有一句代码且方法返回值为void, 则可以省略大括号和分号
() -> System.out.println("方法体中只有一句代码")
  1. 若返回值为不是void, 如果要省略大括号, 且该句唯一代码为return开头的返回值, 则必须省略return关键字
// 该方法return一个true
() -> true

语法学习案例

1. 无参无返回值
/**
 * 函数式接口: 给接口上加上@FunctionInterface注解, 会检查接口是不是函数式接口, 不报错说明就是函数式接口
 */
@FunctionalInterface
interface Animal {

    // 无参无返回值的抽象方法
    void eat();
    
    // 函数式接口中可以有其他方法, 但是抽象方法有且只能有一个
    default void defaultMethod(){
        System.out.println("我是jdk8的特性之一: default默认方法");
    }
}


/**
 * 测试类
 */
public class Test {

    public static void main(String[] args) {

        // lamdaba
        Animal cat1 = () -> {
            System.out.println("我是猫cat1, 我喜欢吃鱼");
            System.out.println("我是猫cat1, 我喜欢抓老鼠");
        };
        cat1.eat();

		// 省略模式:
        // 若代码块中只有一句代码且方法返回值为void, 则可以省略大括号和分号
        // 此处的分号是创建对象的分号, 方法体中的分号已经省略
        Animal cat2 = () -> System.out.println("我是猫cat2, 我喜欢吃鱼, 也喜欢抓老鼠");
        cat2.eat();
    }
}
2. 只有一个参数, 无返回值
@FunctionalInterface
interface Animal {

    // 只有一个参数, 无返回值
    void eat(String food);
}


/**
 * 测试类
 */
public class Test {

    public static void main(String[] args) {

        // lamdaba简写形式: 若是只有一个形参, 则可以不写小括号
        Animal cat = food -> System.out.println("我是猫cat, 我喜欢吃" + food);
        cat.eat("鱼和猫条");
    }
}
3. 有多个参数, 无返回值
@FunctionalInterface
interface Animal {

    // 有多个参数, 无返回值
    void eat(String food, int number);
}


/**
 * 测试类
 */
public class Test {

    public static void main(String[] args) {

        // lamdaba
        Animal cat = (food, num) -> System.out.println("我是猫cat, 我一次要吃" + num + "份" + food);
        cat.eat("鱼", 5);
    }
}
4. 有返回值

有返回值时, 不管有参无参, 跟返回值是void的方法中的区别在于方法体中有无return语句, 其他并无区别, 因此, 此处只演示多个参数有返回值的情况

@FunctionalInterface
interface Calculator {

    // 将两个数字进行相加, 返回结果
    int add(int number1, int number2);
}


/**
 * 测试类
 */
public class Test {

    public static void main(String[] args) {

        // lamdaba
        Calculator calculator = (num1, num2) -> {
            System.out.println("加法运算...");
            return num1+num2;
        };
        calculator.add(10, 5);
    }
}

当方法体中有且只有一条返回语句时, 省略模式如下:

public static void main(String[] args) {

        // 当方法体中只有一条return语句时, 省略模式如下
        Calculator calculator = (num1, num2) -> num1 + num2;
        calculator.add(10, 5);
    }

实际使用案例

创建一个线程并启动

我们先用常规的方式实现

public static void main(String[] args) {

    // 创建一个线程
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("线程: "+Thread.currentThread().getName()+"启动了...");
        }
    }).start();
}

然而, 当你点进Runnable接口后会看见如下源码:
java8特性: lambda表达式语法入门-笔记狂魔_第1张图片
原来Runnable接口也是一个函数式接口, 因此我们可以直接使用lambda表达式来代替匿名内部类:

public static void main(String[] args) {

    // 创建一个线程
    new Thread(() -> System.out.println("线程: "+Thread.currentThread().getName()+"启动了...")).start();
}

使用总结

总之, 只要方法参数中需要让我们传入一个函数式接口的对象, 那么我们就可以使用lambda表达式来将代码简化. 比如HashMap中提供的forEach(BiConsumer action)方法, 也是传入一个函数式接口的对象, 这样, 我们直接调用此方法, 再配合以lambda, 就可以用很简洁的代码对集合进行遍历了

lambda表达式和匿名内部类的区别

语法区别:
  1. 匿名内部类可以是接口, 抽象类, 具体类, Lambda只能是函数式接口
  2. 接口中若是有多个抽象方法, 可以使用匿名内部类创建对象, 但是不能使用Lambda表达式
本质区别:

匿名内部类是new一个新的对象出来, 在编译后会产生单独的一份.calss文件, Lambda表达式在编译时不会产生字节码文件, 在运行时才会动态生成字节码文件

其他

原创作者: 笔记狂魔, 如有错误, 请多指正

你可能感兴趣的:(java8特性,java,lambda,jdk1.8)