【自学】Java核心技术卷1_6.3 lambda表达式

lambda表达式:可传递的代码块,可在以后执行一次或多次

6.3.1 引入lambda的原因:Java是面向对象语言,不能直接传递代码段,必须构造一个对象,这个对象的类需要有一个方法能包含所需代码段,

6.3.2 lambda表达式语法:(参数)->{表达式}

  • 如果无参数:要提供空括号 ()->{}
  • 参数类型可由上下文推导:可以省略参数类型 (a,b)->{}
  • 只有一个参数且其类型可由上下文推导:可以省略参数的类型以及小括号a->{}
  • 无需指定lambda表达式返回类型:总可由上下文推导得出

6.3.3 functional接口:只有一个抽象方法的接口。

  • 可用于创建lambda表达式、方法引用、构造器引用
  • 可以声明别的default方法,因为default方法有实现,所以不是抽象方法;如果接口声明的覆盖了Object类的公开方法的方法也不计入抽象方法,因为任何接口的实现都有从Object类或者别处的实现。
  • 可以在需要这种接口的变量的地方提供lambda表达式(在底层,被传递lambda表达式的方法会接收实现了函数式接口的变量,在这个变量上调用对应方法时,执行lambda表达式的体)

6.3.4 方法引用——已经有现成的方法可以完成想要传递到其他代码的某个动作

  • 遇到重载方法是,编译器会从上下文找
  • 可以在方法引用中使用this参数:this::equals <=> x->this.equals(x)
  • super::instanceMethod:以this为目标,调用给定方法的超类版本

6.3.5 构造器引用 :ClassName::new

  • 将方法引用的方法名改为new即可,编译器根据上下文判断选哪一个构造器。
  • 可以用数组类型建立构造器引用:int[]::new <=> x->new int[x]
  • 将数组构造器引用传入返回Object数组的方法后,此方法可以调用这个构造器得到正确类型的数组返回

6.3.6 变量作用域

  • lambda表达式可以捕获外围作用域中的明确定义且不会改变的变量的值(可以不声明为final,但是后面必须不能改变变量的值)
  • lambda表达式的体与嵌套块有相同的作用域,命名冲突和覆盖规则仍然适用:在lambda表达式中声明一个与局部变量同名的参数或局部变量是不合法的
  • 在lambda表达式使用this时,是指创建这个lambda表达式的方法的this参数

6.3.7 处理lambda表达式

  • 定义方法,方法的参数包含函数式接口变量,然后调用此方法时,给这个函数式接口变量提供lambda表达式,就可以通过此变量执行lambda表达式主体
  • 如果自己设计函数式接口,则可以用@FunctionalInterface注解标记这个接口:一来可以在此接口被增加多余非抽象方法是,让编译器报错,二来在javadoc页会指出此接口是函数式接口

lambda 表达式和匿名类之间的区别

  • 关键字 this:匿名类的 this 关键字指向匿名类;lambda表达式的 this 关键字指向包围lambda表达式的类。
  • 编译方式:匿名内部类被编译为Outter&Inner.class文件; lambda表达式被编译为类的私有方法,使用了Java 7的 invokedynamic 字节码指令来动态绑定这个方法。

lambda表达式常用场景

  • 初始化线程:new Thread(new Runnable(){})。 void run();
  • 事件处理,向一个UI组件添加ActionListener:button.addActionListener(new ActionListener(){});
  • 打印list所有元素:list.forEach(n->System.out.println)) (或方法引用 list.forEach(System.out::println);
  • Predicate<T>创建逻辑测试:boolean test(T)
  • Stream流操作:filter(Predicate);forEach(Consumer);map(Funcion);reduce(BinaryOperator)

个人理解总结:其实只要记住lambda表达式要依附函数式接口来使用,所以任何需要函数式接口变量的地方都可以赋lambda表达式,只需要根据对应的接口中的抽象方法处理好lambda的参数类型和个数,以及返回值即可(其实可以将赋给函数式接口变量的lambda表达式看作对接口抽象方法的实现体)。所以不论是上面的Stream操作还是事件处理等,只要关注函数式接口中的抽象方法即可。

java.util.function包为lambda表达式和方法引用提供了target type

代码对比:用对象的方法传递代码段、匿名内部类、lambda表达式

代码练习

import java.util.function.BiConsumer;
import java.util.function.Function;

public class LambdaTest {
    final static public String str1 = "str1"; //main是static方法,所以str1要声明为static

    public static void main(String args[]) {
        final String str2 = "str2";
        final int num = 2;

        //lambda访问外部局部变量,用Runnable接口
        Runnable runnable = () -> System.out.println("Runnable: " + str1 + " and " + str2);
        runnable.run();
        //接口变量作参数调用lambda
        Function<Integer, Integer> function = n -> n + 1;
        func(num, function);
        func(num, n -> n * n);
        //用lambda替换匿名内部类,用BiConsumer接口
        BiConsumer<String, String> bio = (s1, s2) -> System.out.println("BiConsumer Lambda: " + s1 + " and " + s2);
        bio.accept(str1, str2);
        //匿名内部类对比
        bio = new BiConsumer<String, String>() {
            @Override
            public void accept(String s, String s2) {
                System.out.println("BiConsumer Anonymous: " + s + " and " + s2);
            }
        };
        bio.accept(str1, str2);
    }

    //定义有“函数式接口变量”参数的方法
    public static void func(int x, Function<Integer, Integer> function) {
        System.out.println(function.apply(x));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值