建设信用卡网银网站,咸阳城乡建设局网站,尚品宅配装修公司官网,大连美建科技有限公司文章目录lambda表达式是什么lambda表达式的语法函数式接口初次使用深入理解方法引用 :: 用法快速入门不同形式的::情况1 object::instanceMethod情况2 Class::instanceMethod情况3 Class::staticMethod对于 :: 的一些示例及其注意事项构造器引用变量作用域使用外部变量定义内部…
文章目录lambda表达式是什么lambda表达式的语法函数式接口初次使用深入理解方法引用 :: 用法快速入门不同形式的::情况1 object::instanceMethod情况2 Class::instanceMethod情况3 Class::staticMethod对于 :: 的一些示例及其注意事项构造器引用变量作用域使用外部变量定义内部变量this指向问题lambda的好处常见的函数式接口自己设计一个支持lambda的方法自定义函数式接口总结lambda表达式是什么
lambad表达式是一个可传递的代码块可以在以后执行一次或者多次。
我们都知道java是面向对象的语言我们在进行方法传递时并不能直接传递代码段而是要传递一个对象这个对象中有一个方法包含了想要传递的代码段。
例如Arrays.sort就要一个Comparator接口我们就只能传递一个实现该接口的对象。 Integer[] nums {4, 1, 3, 2};Arrays.sort(nums, new ComparatorInteger() {Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});在其他一些语言中可以直接处理代码块但是java一直没有增加这个特性因为java的强大之处就在于其简单性和一致性。好在在jdk8中加入了一种lambad的设计我们可以使用lambda就可以实现类似代码块传递的功能极大的简化了代码。 我们上面的代码使用lambad就可以改写为如下形式 Integer[] nums {4, 1, 3, 2};Arrays.sort(nums, (o1, o2) - o2 - o1);lambda表达式的语法
这里我先简单说明一下lambda表达式其实就是用来实现某个抽象方法的并且某个抽象类或者接口只有一个抽象方法才能使用lambda表达式。下面的例子也是基于String类型的Comparator中的compare抽象方法 lambda的语法就是 (参数) - {代码逻辑} 我们利用lambda来实现方法一个简单的例子如下 (String s1, String s2) - {return s1.length() - s2.length();};如果代码块里面只有一行语句那么就可以省略大括号直接写在一行
(String s1, String s2) - s1.length() - s2.length();写在一行就可以省略return关键字了 关于lambda并不是一定要有返回值是否要有返回值是却决于要实现的抽象方法是否有返回值的。
对于一个lambda方法在很多情况下都是可以省略参数上面的类型的因为编译器可以推断出
(s1, s2) - s1.length() - s2.length();对于只有一个参数的lambda我们可以省略参数的括号。对于没有参数的lambda我们又必须要写上该括号
s - s.length();() - System.out.println(1);这里介绍了lambda的一些形式看不懂不要紧下面就开始具体说明。
函数式接口
对于只有一个抽象方法的接口需要这种接口的对象时我们就可以提供一个lambda表达式。这种接口就称为函数式接口。
初次使用
我们还是来看一下Arrays.sort方法 该sort方法就需要提供一个实现Comparator的接口。下面再来看一下Comparator接口 这个接口有很多方法但是只有compare是抽象方法其他都有默认实现所以这个就符合函数式接口的定义我们使用Arrays.sort方法时就不需要传入一个实现Comparator的对象只需要传入一个lambda的表达式就行了。
下面就是使用lambda就行排序的例子
public class People {private String name;private Integer age;public People(String name, Integer age) {this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age age;}Overridepublic String toString() {return People{ name name \ , age age };}
}
我们有一个People对象数组现在要求对这个数组进行排序排序要求为按照名称的长度排序升序 People[] people {new People(cc, 19),new People(ttpfx, 21),new People(tom, 26),new People(lucy, 20)};我们要使用lambda表达式首先要搞清楚用lambda所对应的抽象方法我们这里要实现的方法就是compare方法传入2个参数返回一个int 这里的T就是一个泛型由于我们是对People排序所以T就是代表People对象。知道了这些我们就可以写lambda表达式了。
Arrays.sort(people, (p1, p2) - p1.getName().length() - p2.getName().length());上面的代码就可以实现People数组按照名称长度升序排列
对应lambda表达式我们最好将其看作是一个函数而不是一个对象。
深入理解
对于上面lambda表达式我们还可以简写形式如下
Arrays.sort(people, Comparator.comparingInt(p - p.getName().length()));对于上面的表达式我来进行说明一下由于Arrays.sort需要一个Comparator所以我们需要提供一个Comparator但是Comparator.comparingInt会返回一个Comparator。所以没问题 又由于comparingInt需要接受一个ToIntFunction我们再来看一下ToIntFunction 可以发现ToIntFunction就只有一个抽象方法所以我们又可以使用lambda表达式最终的形式就是下面那样的。
Arrays.sort(people, Comparator.comparingInt(p - p.getName().length()));对于泛型默认大家都是很了解的这篇文章不会进行讲解如果感觉有点看不懂了请先去学习泛型
方法引用 :: 用法
快速入门
有的时候如果我们lambda涉及到一个方法例如我们创建了一个定时器要求每秒打印一下这个事件对象代码如下
Timer timer new Timer(1000, event - System.out.println(event));这里为什么可以使用lambda表达式大家应该都可以猜出来了原因就是Timer的第二个参数是应该函数式接口只有一个抽象方法Timer的第二个参数内容如下。 对于上面的写法我们可以简写为如下形式
Timer timer new Timer(1000, System.out::println);对于 System.out::println 这个写法可能已经很多人蒙了这是啥东西啊。其实 System.out::println 就是一个方法引用就代表引用System.out对象的println方法。System.out::println指示编译器生成一个函数式接口的实例覆盖这个接口的抽象方法来调用给定的方法。相信大家看完还是很蒙下面就再通俗的解释一下。
我们通过ActionListener源代码可以发现actionPerformed会传入一个 ActionEvent对象 e返回值为void也就是没有返回值。我们再来看一下System.out的println的方法 可以发现println接受一个Object的参数返回值也是void我们将 actionPerformed 和 println 进行对比是不是发现很相似呢对于actionPerformed 的参数我们也可以通过Object来进行接收。我们再lambda表达式里面编写的逻辑就是打印参数println的任务就是打印既然如此那为什么我们不直接将println这个方法用来覆盖actionPerformed 掉方法呢事实上System.out::println我们就是用println方法覆盖掉了actionPerformed 方法我们调用actionPerformed(e)时实际上就是调用println(e)方法了。
对于上面的说明仅仅为个人的理解。如果有误还请在评论区指出。
如果要使用 :: 形式的lambda表达式必须返回值相同参数个数相同参数类型相同或者为父类
不同形式的::
对于使用::分隔方法名与对象名或类名主要有以下3种情况
object::instanceMethodClass::instanceMethodClass::staticMethod
情况1 object::instanceMethod
在第一种情况下方法引用等价于向方法传递参数的lambda的表达式。例如上面的System.out::printl1n就等价于 x - System.out.println(x)
情况2 Class::instanceMethod
对于这种情况我先举一个例子现在有一个要求就是对String数组按照字母升序排列忽略大小写 String[] names {Tom, CC, tTpfx, JURY};对于上面的要求经过上面要求我们该怎么完成呢通过上面的lambda的学习我们可以通过lambda表达式完成我们调用compareToIgnoreCase这个方法进行比较就行了 Arrays.sort(names, (name1, name2) - name1.compareToIgnoreCase(name2));我们来看一下compareToIgnoreCase的源代码 可以发现这个和我们要传入Comparator的compare方法参数和返回类型都是一样这样那我们岂不是就可以使用::的写法了。也确实是这样的。::写法如下 Arrays.sort(names, String::compareToIgnoreCase);可以发现十分的简洁。
经过上面的例子现在就可以对上面的 Class::instanceMethod 进行说明了Class就代表类名instanceMethod 就代表静态方法。对于这种情况第一个参数就会成为隐式参数。也就是说String::compareToIgnoreCase 相当于 (name1, name2) - name1.compareToIgnoreCase(name2)
情况3 Class::staticMethod
这种情况就不举例了理解了情况2现在来理解这个很简单。Class::staticMethod就相当于将所有参数传递到参数列表例如 Math::pow 就等价于 (a,b) - Math.pow(a,b)
对于 :: 的一些示例及其注意事项
下图就是::的一些示例 对于::的注意事项如下
只有当lambda表达式的体只调用一个方法并且不做其他操作时才可以把lambda表达式重写为方法引用如果要引用的方法具有多个重载的方法编译器会找出最相似的方法方法引用不能单独存在总是会转换为函数式接口的实例包含对象的方法引用与等价的lambda表达式还有一个细微的差别。考虑一个方法法引用如separator::equals.。如果separator为null,构造separator::equals时就会立抛出一个异常。lambda表达式x - separator.equals(x)只在调用时才会拋出NullPointerException。对于::我们可以使用this和superthis代表当前类super表示父类
构造器引用
构造器引用和方法引用很类似只不过将方法名换成了new下面就是应该例子
public class Cat {public Cat() {}public Cat(Cat cat) {}
}下面代码将一个集合转换为数组 Testpublic void t4() {ListCat list new ArrayList();list.add(new Cat());list.add(new Cat());StreamCat stream list.stream().map(Cat::new);Cat[] cats stream.toArray(Cat[]::new);System.out.println(Arrays.toString(cats));}里面的第一个Cat::new 就代表引用构造器。相当于 c - new Cat© 第二个Cat[]::new 相当于 x - new Cat[x]
变量作用域
使用外部变量
在lambda表达式中我们使用的外部变量必须是最终变量或实际上的最终变量。 例如下面代码是没有问题的 Testpublic void t1() {int i 1;Integer[] nums {2, 1, 3};Arrays.sort(nums, (n1, n2) - {System.out.println(i);return n2 - n1;});System.out.println(Arrays.toString(nums));}我们在lambda里面打印i的值没有任何问题。但是我们如果将i的值改变 Testpublic void t1() {int i 1;Integer[] nums {2, 1, 3};i;Arrays.sort(nums, (n1, n2) - {System.out.println(i);return n2 - n1;});System.out.println(Arrays.toString(nums));}此时再运行编译器就会输出如下信息 IDEA也会给出以下提示告诉我们变量的值是不能够改变的 定义内部变量
对于lambda表达式我们再里面还不能够定义与外部变量相同的参数名称例如下面代码 Testpublic void t1() {int i 1;Integer[] nums {2, 1, 3};Arrays.sort(nums, (n1, n2) - {int i 0;return n2 - n1;});System.out.println(Arrays.toString(nums));}我们再lambda里面定义了与外部变量同名的i变量这时候IDEA就会给出以下提示 如果运行就会报错 this指向问题
在lambda里面的this就是创建lambda那个方法的this。 Testpublic void t2() {Integer[] nums {2, 1};System.out.println(this.getClass().hashCode());Arrays.sort(nums, (n1, n2) - {System.out.println(this.getClass().hashCode());return n2 - n1;});}上面代码输出如下 也就代表这两个this是一样的。
lambda的好处
我们使用lambda的重点就是延迟执行lambda只有在调用时才会执行。对于为什么需要延迟执行参考下面的几点
在一个单独的线程中运行代码多次运行代码在算法的适当位置运行代码例如排序中的比较操作发生某种情况时执行代码如点击了一个按钮数据到达等等只在必要时才运行代码
常见的函数式接口
我们如果也想要编写支持lambda表达式的方法我们就可以使用函数式接口来完成不需要自己再去定义接口下面就会列出一些常见的函数式接口 下图列出了基本类型int、long和double的34个可用的特殊化接口。使用这些特殊化接口比使用通用接口更高效。这些后面的博客中会进行说明 自己设计一个支持lambda的方法
我们就使用上面提供的一些函数式接口来设计一个支持lambda的方法 这个方法就使用到了Predicate这个函数式接口对于这个接口忘了请参考如下 该接口源代码为 我们设计的方法如下
public class DesignLambdaMethod {public static T ListT filterList(ListT list, PredicateT predicate) {ListT tList new ArrayList();for (T t : list) {if (predicate.test(t)) {tList.add(t);}}return tList;}
}这个方法接收一个List然后接收一个Predicate如果Predicate中的test方法返回为真那么我们就不进行处理否则就将其移除List。这个方法就可以用于过滤List。 具体使用如下 public static void main(String[] args) {ListString list Arrays.asList(tom, jack, ttpfx, mike, lc);System.out.println(list);// 要求过滤掉list中的长度小于等于3的字符串ListString newList filterList(list, s - s.length() 3);System.out.println(newList);}上面的程序运行后输出如下成功完成需求 自定义函数式接口
对于函数式接口的定义想必大家已经很清楚了只需要在接口有且只有抽象方法就是一个函数式接口。下面就是自定义的一个函数式接口
public interface MyInterface {R void apply(R r);
}对于函数式接口我们可以使用FunctionalInterface进行标识。这样做有2个优点如下
如果你无意中增加了另一个抽象方法编译器会产生一个错误消息javadoc页里会指出你的接口是一个函数式接口。
FunctionalInterface
public interface MyInterface {R void apply(R r);
}如果使用FunctionalInterface后我们再增加一个抽象方法那么就会出现以下错误信息 最后需要说明的是并不是一定要FunctionalInterface接口但是建议所有的函数式接口都使用该接口进行标识
总结
相信大家经过上面的讲解对于lambda应该已经有了些大概的了解。这篇文章是根据我自己对lambda的理解写出的如果讲解中有错误的地方还请评论区指出共同提高 文章转载自: http://www.morning.rqgq.cn.gov.cn.rqgq.cn http://www.morning.jtcq.cn.gov.cn.jtcq.cn http://www.morning.wynnb.cn.gov.cn.wynnb.cn http://www.morning.njnqn.cn.gov.cn.njnqn.cn http://www.morning.deupp.com.gov.cn.deupp.com http://www.morning.rjmd.cn.gov.cn.rjmd.cn http://www.morning.qbkw.cn.gov.cn.qbkw.cn http://www.morning.pzrrq.cn.gov.cn.pzrrq.cn http://www.morning.crhd.cn.gov.cn.crhd.cn http://www.morning.ytnn.cn.gov.cn.ytnn.cn http://www.morning.hrzymy.com.gov.cn.hrzymy.com http://www.morning.ygxf.cn.gov.cn.ygxf.cn http://www.morning.lkbyj.cn.gov.cn.lkbyj.cn http://www.morning.bnlkc.cn.gov.cn.bnlkc.cn http://www.morning.mrncd.cn.gov.cn.mrncd.cn http://www.morning.bnkcl.cn.gov.cn.bnkcl.cn http://www.morning.kyhnl.cn.gov.cn.kyhnl.cn http://www.morning.xxgfl.cn.gov.cn.xxgfl.cn http://www.morning.ktmbp.cn.gov.cn.ktmbp.cn http://www.morning.bpmz.cn.gov.cn.bpmz.cn http://www.morning.rpwht.cn.gov.cn.rpwht.cn http://www.morning.lkgqb.cn.gov.cn.lkgqb.cn http://www.morning.yjmlg.cn.gov.cn.yjmlg.cn http://www.morning.cbynh.cn.gov.cn.cbynh.cn http://www.morning.kgcss.cn.gov.cn.kgcss.cn http://www.morning.rkfwr.cn.gov.cn.rkfwr.cn http://www.morning.lltdf.cn.gov.cn.lltdf.cn http://www.morning.cmldr.cn.gov.cn.cmldr.cn http://www.morning.yzfrh.cn.gov.cn.yzfrh.cn http://www.morning.xhlpn.cn.gov.cn.xhlpn.cn http://www.morning.pumali.com.gov.cn.pumali.com http://www.morning.mlhfr.cn.gov.cn.mlhfr.cn http://www.morning.rnwmp.cn.gov.cn.rnwmp.cn http://www.morning.rnmdp.cn.gov.cn.rnmdp.cn http://www.morning.rcww.cn.gov.cn.rcww.cn http://www.morning.qkqjz.cn.gov.cn.qkqjz.cn http://www.morning.njstzsh.com.gov.cn.njstzsh.com http://www.morning.rkqzx.cn.gov.cn.rkqzx.cn http://www.morning.dfndz.cn.gov.cn.dfndz.cn http://www.morning.rglp.cn.gov.cn.rglp.cn http://www.morning.zmwd.cn.gov.cn.zmwd.cn http://www.morning.xinxianzhi005.com.gov.cn.xinxianzhi005.com http://www.morning.bpds.cn.gov.cn.bpds.cn http://www.morning.yqgny.cn.gov.cn.yqgny.cn http://www.morning.tkrwm.cn.gov.cn.tkrwm.cn http://www.morning.nmnhs.cn.gov.cn.nmnhs.cn http://www.morning.nwfxp.cn.gov.cn.nwfxp.cn http://www.morning.wqjpl.cn.gov.cn.wqjpl.cn http://www.morning.rlzxr.cn.gov.cn.rlzxr.cn http://www.morning.dfqmy.cn.gov.cn.dfqmy.cn http://www.morning.bqfpm.cn.gov.cn.bqfpm.cn http://www.morning.wxgd.cn.gov.cn.wxgd.cn http://www.morning.smyxl.cn.gov.cn.smyxl.cn http://www.morning.pwxkn.cn.gov.cn.pwxkn.cn http://www.morning.gllhx.cn.gov.cn.gllhx.cn http://www.morning.mkfr.cn.gov.cn.mkfr.cn http://www.morning.hotlads.com.gov.cn.hotlads.com http://www.morning.kkwbw.cn.gov.cn.kkwbw.cn http://www.morning.pmtky.cn.gov.cn.pmtky.cn http://www.morning.kpyyf.cn.gov.cn.kpyyf.cn http://www.morning.bzqnp.cn.gov.cn.bzqnp.cn http://www.morning.jrhcp.cn.gov.cn.jrhcp.cn http://www.morning.lnfkd.cn.gov.cn.lnfkd.cn http://www.morning.zdxss.cn.gov.cn.zdxss.cn http://www.morning.rsszk.cn.gov.cn.rsszk.cn http://www.morning.ymrq.cn.gov.cn.ymrq.cn http://www.morning.sxfmg.cn.gov.cn.sxfmg.cn http://www.morning.xlclj.cn.gov.cn.xlclj.cn http://www.morning.hongjp.com.gov.cn.hongjp.com http://www.morning.qxwgx.cn.gov.cn.qxwgx.cn http://www.morning.ghlyy.cn.gov.cn.ghlyy.cn http://www.morning.ldynr.cn.gov.cn.ldynr.cn http://www.morning.ey3h2d.cn.gov.cn.ey3h2d.cn http://www.morning.rfwrn.cn.gov.cn.rfwrn.cn http://www.morning.qnhcx.cn.gov.cn.qnhcx.cn http://www.morning.mwkwg.cn.gov.cn.mwkwg.cn http://www.morning.dsmwy.cn.gov.cn.dsmwy.cn http://www.morning.ygbq.cn.gov.cn.ygbq.cn http://www.morning.3jiax.cn.gov.cn.3jiax.cn http://www.morning.dtnzk.cn.gov.cn.dtnzk.cn