java8 - Lambda表达式

1.先了解下什么是Lambda表达式
  • Lambda表达式可以理解为可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。
  • Lambda表达式可以作为参数传递给方法或存储在变量中 Lambda表达式是简洁的
2.Lambda表达式的组成

lambda参数、->、lambda主体
示例:(int x,int y)-> {return x+y;}

3.Lambda基本语法

(parameters) -> expression 或
(parameters) -> { statements; }

4.Lambda如何使用
函数式接口:只定义一个抽象方法的接口

    有一个注意的点:在java8中接口可以有默认的实现(即在类没有对方法进行实现时,其主体为方法提供默认实现的方法),除了默认的方法,抽象方法有且只有一个才能算函数式接口

    Lambda表达式允许你直接内联,为函数式接口的抽象方法提供实现,并且将整个表达式作为函数式接口的一个实例。

函数描述符:函数式接口的抽象方法的签名(这里的签名指的是抽象方法的参数与返回类型)
行为参数化:以前我们写的方法都是将某个值或者Object作为参数在方法内部进行相对应得操作,行为参数化则是将操作值或者Object的行为作为参数传递

示例:
    从一个文件中读取内容,通过行为参数化来进行不同的操作

1.定义一个readFile的Operation接口,这个接口就是一个函数式接口,它符合函数式接口的定义,有且只有一个抽象接口
@FunctionalInterface
public interface Operation {
    public String readFile(BufferedReader bufferedReader) throws IOException;
}

2.在readOperation中使用operation接口的readFile方法,这一个方法的行为会在第3步给出来
public class FileOperation {

    public String readOperation(Operation operation) throws IOException {
        //此处是java 7中新加的语法糖,带资源的try语句不再需要我们显式的去关闭资源
        try(BufferedReader bufferedReader = new BufferedReader(new FileReader("data.txt"))){
            return operation.readFile(bufferedReader);
        }
    }

}
3.将不同的行为参数化,传递不同的Lambda表达式就可以有不同的方式处理文件内容
  String line1 = readOperation((BufferedReader bufferedReader) -> bufferedReader.readLine());
  String line2 = readOperation((BufferedReader bufferedReader) -> bufferedReader.readLine()+bufferedReader.readLine());
注明:

    a.@FunctionalInterface
在java8中,新的java API通过@FunctionalInterface来标注函数式接口,这个标注用于表示该接口会设计成一个函数式接口,标注的接口有多个抽象接口(没有默认实现),会编译异常“Multiple non-overriding abstract methods found in interface xxxInterface”,@FunctionalInterface不是必需的

    b.任何函数式接口都不允许抛出受检异常(checked exception)。如果你需要Lambda表达式来抛出异常,有两种办法:定义一个自己的函数式接口,并声明受检异常,或者把Lambda包在一个try/catch块中。

5.Lambda表达式中的类型检查、类型推断
Lambda表达式中的类型检查

    Lambda的类型是从使用Lambda的上下文推断出来的。上下文(比如,接受它传递的方法的参数,或接受它的值的局部变量)中Lambda表达式需要的类型称为目标类型。

检查过程:

1.找出方法的声明
    比如:public String readOperation(Operation operation) throws IOException
2.找到目标类型,比如Predicate<T -> Object>
    T -> Object:T绑定到某一个对象,如:String、自定义对象 等
3.找到函数式接口中定义的抽象方法
4.抽象方法描述了一个函数描述符,它接收的参数以及返回的类型
5.方法的任何实际参数都必须匹配这个要求

标注:

    只要不同抽象方法的参数与返回类型兼容,同一个Lambda表达式就可以与不同的函数式接口联系起来

Callable<Integer> c = () -> 42;
PrivilegedAction<Integer> p = () -> 42;
类型判断:

    Java编译器可以从上下文(目标类型)推断出用什么函数式接口来配合Lambda表达式
进一步简化了Lambda表达式的写法

--没有类型推断,参数bufferedReader有显示参数
String line1 = readOperation((BufferedReader bufferedReader) -> bufferedReader.readLine());

--有类型推断,参数bufferedReader没有有显示参数
String line3= readOperation(bufferedReader -> bufferedReader.readLine());

--只有一个参数的时候,参数两边的括号也能省略
Operation operation = bufferedReader -> bufferedReader.readLine();
6.Lambda和局部变量
  • Lambda允许使用方法主体外的变量,如同匿名内部类一样,这样的Lambda表达式称为捕获Lambda-
  • Lambda使用这些变量是有限制的,只能是final修饰的变量
为什么会有这个限制

    1.存储的位置不同,实例变量存储在堆上,局部变量存储在栈上
    2.Lambda 表达在另一个线程中执行,也就是可能存在局部变量在被回收掉的情况下,去访问该局部变量;在用final修饰的情况下,去访问的只是这个变量的副本

--正常
    int a = 10;
    Runnable runnable = () -> System.out.println(a);
    
--编译报错
--Error:从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量
    int a = 10;
    Runnable runnable = () -> System.out.println(a);
    
    a = 19;
总结:
  • Lambda没有return语句,return语句是隐藏的 Lambda表达式可以包含多行语句 Lambda参数可以存在多个,也可以为0个
  • Lambda表达式允许直接内联,为函数式接口的抽象方法提供实现,并且将整个表达式作为函数式接口的一个实例
  • Lambda表达式的签名要与函数式接口中定义的抽象方法签名要一致 Lambda表达式会自动去推断类型
  • Lambda表达式可以使用除主体外的变量,且主体外的变量必须用final修饰
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值