本文共 3523 字,大约阅读时间需要 11 分钟。
Lambda表达式也可称为闭包,是Java 8的重要更新,也是一个被广大开发者期待已久的新特性。Lambda表达式支持将代码作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例。
Oracle 公司于 2014 年 3 月 18 日发布 Java 8,Lambda从2014年到2019年已经有5个年头的生命了,可以在实际的项目中的应用其实还是有限的,最主要的原因应该包括以下几个方面:
Lambda使用的目的:
因为Lambda是甜食,所以理解后,总是能尝到些甜头的,所以大家还是耐心的学习一下Lambda吧。
先来看看Lambda的直接使用的例子吧--匿名内部类的替换:
//匿名内部类方式创建线程,启动public void oldRunable() { Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("The old runable now is using!"); } }); t.start();}//lambda方式创建线程,启动public void runable() { Thread t2 = new Thread(() -> System.out.println("It's a lambda function!")); t2.start();}
结果显而易见的lambda极大程度的简化了代码,代码的关键技术是创建一个Runnable接口的对象,重写接口里面的run方法,将这个对象传递到Thread的构造器里,让我们看看Lambda简化了什么:
lambda就是想尽一切方式简化代码,编译器能推理出来的东西交给机器去处理,程序员只要按照机器认识的方式编写必要出现的代码。
Lambda的语法定义,它由三部分组成
例子:来看看最全的写法(String a)-> { return a + "," ;}
简化后的写法: a -> a + "," (省了“()”,省了类型,省了return,省了花括号)
自己一定要多练习几个写法,这样再见到各种奇怪的Lambda写法就眼熟了。
至此你已经对Lambda的写法“了如指掌”,接下来要学习另一个新知识。
其实看了上面的内容对于Lambda的理解除了写法,也起不到别的作用,这里要介绍一个“目标类型(target type)”,
Lambda表达式的目标类型必须是“函数式接口(functional interface)”。函数式接口:只包含一个抽象方法的接口。接口可以包含多个默认方法、类方法,但关键是一个抽象方法。
Java8 的函数式接口有很多,如:Runnable,ActionListener,Filter,Comparator,新添加的Function,Predicate等,java8专门为函数式接口提供了@FunctionalInterface注解,可以使用此注解编写函数式接口,限制接口编写非函数式接口内容。
说白点就是Lambda表达式是要创建一个接口的对象,对象的类型是只有一个抽象方法的接口,来看看。
Runnable r = () -> System.out.println("我是java老手");
=号右面的是Lambda表达式,左边的是函数式接口,那么现阶段能使用Lambda的地方一下子就限制住了就给那“几个”接口来用。
哪里使用函数式接口,哪里就有Lambda
Lambda对比传统写法已经很简洁了,可以你以为上面的写法就是最简洁的了吗?不是。在上面Lambda的的语法定义中,如果Lambda表达式的代码块只有一条代码,还可以再代码块中使用方法引用和构造器引用。
Lambda的使用已经完成了,方法引用只有一点好处就是“简单代码”,不过缺点也明显不易理解和阅读不便,如果你完全不使用方法引用没问题,你所看的所有方法引用都可以换成原始Lambda表达式。
方法引用和构造器引用可以让Lambda表达式的代码在简洁的基础上再简洁,使用::双冒号来使用方法引用,看看有几种引用方式:
下面是一组例子,教你使用方法引用代替Lambda表达式:
//c1 与 c2 是一样的(静态方法引用)
Comparator<Integer> c2 = (x, y) -> Integer.compare(x, y); Comparator<Integer> c1 = Integer::compare; //下面两句是一样的(实例方法引用1) persons.forEach(e -> System.out.println(e)); persons.forEach(System.out::println); //下面两句是一样的(实例方法引用2) persons.forEach(person -> person.eat()); persons.forEach(Person::eat); //下面两句是一样的(构造器引用) strList.stream().map(s -> new Integer(s)); strList.stream().map(Integer::new);方法引用虽然精炼到了极致,可是使用时候阅读不易,所以请酌情。。。
@Testpublic void test1(){ //将为列表中的字符串添加前缀字符串 String a= "lambda :"; ListproStrs = Arrays.asList(new String[]{"Ni","Hao","Lambda"}); List execStrs = proStrs.stream().map(b-> { Long c= System.currentTimeMillis(); return a + b+ " -----:" + c; }).collect(Collectors.toList()); execStrs.forEach(System.out::println);}
输出:
lambda :Ni -----:1498722594781lambda :Hao -----:1498722594781lambda :Lambda -----:1498722594781
变量a :外部变量
变量b:传递变量
变量c:内部自定义变量
lambda表达式可以访问给它传递的变量,访问自己内部定义的变量,同时也能访问它外部的变量。不过lambda表达式访问外部变量有一个非常重要的限制:变量不可变(只是引用不可变,而不是真正的不可变)。
Java中内部类以及Lambda表达式中也不允许修改外部类中的变量。
说了这么多Lambda表达式,目前使用最多的就是集合框架的应用,本章只是对Lambda语法的使用作介绍,以这章为基础的前提下再学习其应用。
将在下一章中给大家带来Lambda的主要使用场景--Stream流API的使用。
(完)
转载地址:http://eqhgf.baihongyu.com/