为什么要使用lambda表达式?原来如此,涨知识了
先看几段Java8以前经常会遇到的代码:
创建线程并启动
比较数组
给按钮添加单击事件
对于这三段代码,我们已经司空见惯了。
Java复杂冗余的代码实现一直被程序员所诟病,好在随着JVM平台语言Scala的兴起以及函数式编程风格的风靡,让Oracle在Java的第8个系列版本中进行了革命性的变化,推出了一系列函数式编程风格的语法特性,比如Lambda表达式以及Stream。
如果采用Lambda表达式,上面三段代码的实现将会变得极为简洁。
创建线程并启动(采用Lambda版本)
比较数组(采用Lambda版本)
给按钮添加单击事件(采用Lambda版本)
格式:(参数) -> 表达式
其中:
一个参数
多个参数
0个参数
表达式块
在Java8中新增加了一个注解: [@FunctionalInterface],函数式接口。
什么是函数式接口呢?它包含了以下特征:
Lambda表达式的本质就是函数式接口的匿名实现。只是把原有的接口实现方式用一种更像函数式编程的语法表示出来。
Java8的java.util.function包已经内置了大量的函数式接口,如下所示:
从中可以看出:
以下是一个综合的例子:
如果觉得这些内置函数式接口还不够用的话,还可以自定义自己的函数式接口,以满足更多的需求。
如果Lambda表达式已经有实现的方法了,则可以用方法引用进行简化。 方法引用的语法如下:
这样前面提到的Lambda表达式:
则可以替换为:
另一个例子:
可以替换为:
注意:方法名后面是不能带参数的! 可以写成System.out::println,但不能写成System.out::println(“hello”)
如果能获取到本实例的this参数,则可以直接用this::实例方法进行访问,对于父类指定方法,用super::实例方法进行访问。
下面是一个例子:
构造器引用和方法引用类似,只不过函数接口返回实例对象或者数组。 构造器引用的语法如下:
举个例子:
其中的labels.stream().map(Button::new)相当于 labels.stream().map(label->new Button(label))
再看个数组类型的构造器引用的例子:
把Stream直接转成了数组类型,这里用Button[]::new来标示数组类型。
先看一段代码:
一个lambda表达式一般由以下三部分组成:
参数和表达式好理解。那自由变量是什么呢? 它就是在lambda表达式中引用的外部变量,比如上例中的text和count变量。
如果熟悉函数式编程的同学会发现,Lambda表达式其实就是”闭包”(closure)。只是Java8并未叫这个名字。 对于自由变量,如果Lambda表达式需要引用,是不允许发生修改的。
比如下面的代码:
先说说为什么要在Java8接口中新增默认方法吧。
比如Collection接口的设计人员针对集合的遍历新增加了一个forEach()方法,用它可以更简洁的遍历集合。 比如:
但如果在接口中新增方法,按照传统的方法,Collection接口的自定义实现类都要实现forEach()方法,这对广大已有实现来说是无法接受的。
于是Java8的设计人员就想出了这个办法:在接口中新增加一个方法类型,叫默认方法,可以提供默认的方法实现,这样实现类如果不实现方法的话,可以默认使用默认方法中的实现。
一个使用例子:
默认方法的加入,可以替代之前经典的接口和抽象类的设计方式,统一把抽象方法和默认实现都放在一个接口中定义。这估计也是从Scala的Trait偷师来的技能吧。
除了默认方法,Java8还支持在接口中定义静态方法以及实现。
比如Java8之前,对于Path接口,一般都会定义一个Paths的工具类,通过静态方法实现接口的辅助方法。
接口中有了静态方法就好办了, 统一在一个接口中搞定!虽然这看上去破坏了接口原有的设计思想。
这样Paths类就没什么意义了~
使用Lambda表达式后可以大幅减少冗余的模板式代码,使把更多注意力放在业务逻辑上,而不是复制一堆重复代码, 除非你在一个用代码行数来衡量工作量的公司,你觉得呢?
Lambda 表达式
Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。 JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。 在创建线程并启动时可以使用匿名内部类的写法; IntBinaryOperator是一个接口,使用匿名内部类的写法调用该方法; IntPredicate是一个接口。先使用匿名内部类的写法调用该方法; Function是一个接口,先使用匿名内部类的写法调用该方法; IntConsumer是一个接口,先使用匿名内部类的写法调用该方法; Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作。 Stream可以由数组或集合创建,对流的操作分为两种: Stream特性: Stream创建方式有三种: map,可以将一个流的元素按照一定的映射规则映射到另一个流中; map,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 filter,对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中; filter,按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。 distinct,去除流中的重复元素; sorted(),自然排序,流中元素需实现Comparable接口; sorted(Comparator com),Comparator排序器自定义排序。 limit,可以设置流的最大长度,超出的部分将被抛弃; skip,跳过流中的前n个元素,返回剩下的元素; flatMap,接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流; map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。 forEach方法,通过 Lambda 表达式的方式遍历集合中的元素; forEach,对流中的元素进行遍历操作,通过传入的参数去指定对遍历到的元素进行什么具体操作。 count,用来获取当前流中元素的个数; max&min,可以用来或者流中的最值。 collect,把当前流转换成一个集合; collect,把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合;流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。 reduce,把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作; reduce,对流中的数据按照你指定的计算方式计算出一个结果。 文章来自https://www.cnblogs.com/HOsystem/p/16084816.html