高阶函数
了解Lamda表达式之前,我们先来了解一下什么是高阶函数。
在数学和计算机领域中,高阶函数是至少满足以下两个条件中一个:
1.接受一个或多个函数作为输入
2.输出一个函数
为什么使用Lamda
相信大家除了Java语言也接触过类似于JavaScript或者Scala等脚本语言,这些语言是支持高阶函数的,也大都同时满足以上的两点。Scala语言本身就依赖于JVM,所以对于Java语言实现高阶函数也是完全,没有问题的。在JDK8中,Lamda表达式就是专门来实现Java的函数式编程。
可能有一些小伙伴还没有太多的使用JDK8的版本,就会想Lamda表达式能给我们带来什么呢?代码的简化以及可读性,Lamda表达式加链式调用会让代码看起来通俗易懂。话不多说,先看一个简单的栗子吧~
// JDK8之前的代码
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread run!!!");
}
}).start();
// Lamda表达式的代码
new Thread(()->{System.out.println("thread run!!!");}).start();
在代码上的整洁程度来说显而易见,如果有了Lamda表达式我们很大程度上就可以告别恶心的匿名内部类(思考一下匿名内部类的特质,比如变量的可见性,Lamda表达式是怎样的,需要遵守么),尤其是有多次调用的情况,可以通过链式调用来表达,更加的条理和人性化。
如何申明一个Lamda表达式接口
1.申明一个接口,加入类注解@FunctionalInterface,保证接口中未实现的方法有且只有一个,接口默认方法不计算在内,如果不信的话,你可以试试,多个的话就会编译报错(这里需要思考一下为什么是一个,我个人觉得这里是Java为了实现函数式编程进行了“强扭的瓜”,的确是不太“甜”,内部的实现应该还是内部类的逻辑,这里是猜测)
@FunctionalInterface
public interface LamdaInterface {
public String apply(String name);
// 默认函数可以有
default String addLastName(String name) {
return apply(name) + "Curry";
}
}
2.完成需要完成逻辑,就像填空题一样,所有的内容都完成了,只留下一个需要空来填,这要填的空就是要实现的函数逻辑。
public class NBAPlayer {
public String firstName;
// 具体结果还要依赖于接口方法的实现。这里就是我们要填的空
public void printName(LamdaInterface lamdaInterface) {
System.out.println(lamdaInterface.addLastName(this.firstName));
}
}
- 根据Lamda表达式实现内容
public static void main(String[] args) throws Exception{
NBAPlayer nbaPlayer = new NBAPlayer();
nbaPlayer.firstName = "Stephen";
nbaPlayer.printName(name->name+"·");
}
完整的步骤需要这三步,看到这里小伙伴们是不是觉得我忽悠你们了,这个写的代码感觉也不是很少呀,还是很痛苦。其实在实际开发的过程中,第1步是不需要我们自己做的,JDK在java.util.function包下有很多实例,涵盖了大部分的情况,所以不需要自己写函数式接口。大部分情况下第2步也是不需要自己做,因为大部分情况下都是去调用第三方的jar,这部分逻辑都已经实现,如果在一个团队中不是基础平台的开发人员的话,这一步接触的也比较少一点。所以对于我们来说其实只要把第三步完全掌握了就OK了。下面我们看一下JDK给我们提供的常见的函数式接口。
JDK提供的函数式接口
- Talk is cheap,show the code.
@FunctionalInterface
public interface Consumer<T> {
void accept(T var1);
default Consumer<T> andThen(Consumer<? super T> var1) {
Objects.requireNonNull(var1);
return (var2) -> {
this.accept(var2);
var1.accept(var2);
};
}
}
- Talk is cheap,show the code.
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
- Talk is cheap,show the code.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T var1);
default Predicate<T> and(Predicate<? super T> var1) {
Objects.requireNonNull(var1);
return (var2) -> {
return this.test(var2) && var1.test(var2);
};
}
default Predicate<T> negate() {
return (var1) -> {
return !this.test(var1);
};
}
default Predicate<T> or(Predicate<? super T> var1) {
Objects.requireNonNull(var1);
return (var2) -> {
return this.test(var2) || var1.test(var2);
};
}
static <T> Predicate<T> isEqual(Object var0) {
return null == var0 ? Objects::isNull : (var1) -> {
return var0.equals(var1);
};
}
}
- Talk is cheap,show the code.
@FunctionalInterface
public interface Supplier<T> {
T get();
}
上面的四种是我个人认为很常用的四种,就把JDK源码列出来了,大家看代码就好了,如果还需要其他形式的,建议先去java.util.function包下找一下,如果没有的话,再自己去新建。第一步搞定了,第二部其实主要就是实现的逻辑,没啥好说的,接下来看第三步的写法。
Lamda表达式常见写法
公共代码,下面会用到
@FunctionalInterface
interface inter1 {
String said(String sm);
}
@FunctionalInterface
interface inter2{
Employee getEmployee(String name, String address, int salary, int age);
}
class Robot{
public String robotGun;
public void attack (inter1 inter1) {
String attack = inter1.said(robotGun);
System.out.println(attack);
}
}
class Attack{
public static String attack(String said) {
return "Attack!!!!!!!" + said;
}
public String shot(String said) {
return "Shot!!!!!!!" + said;
}
public Employee getEmployee(inter2 inter2,String name, String address, int salary, int age) {
return inter2.getEmployee(name, address, salary, age);
}
}
- 无参数,必须加括号,如果方法体的内容就一句话其实是可以不加花括号的
Thread thread = new Thread(() -> {System.out.println(1);});
thread.start();
2.一个参数,一个参数方法头可以省略括号
Robot robot = new Robot();
robot.robotGun = "AWM";
robot.attack(said -> said + " attack!");
3.多个参数,如果体部是一句话以上的必须加花括号
List<Integer> list = Arrays.asList(99,55,66,88);
Collections.sort(list, (x,y) -> x - y);
for(Integer num : list) {
System.out.println(num);
}
4.引用静态方法
Attack attack = new Attack();
robot.attack(Attack::attack);
5.引用实例对象方法
robot.attack(attack::shot);
6.引用构造方法
inter2 inter2 = Employee :: new;
Employee employee = attack.getEmployee(inter2, "xusq", "shanxi", 30000, 18);
System.out.println(employee.toString());
以上我列出来的常见的Lamda表达式的写法,如果觉得不是很懂的话,就都忘了吧,你只需要记住,我们要传入的是一个函数就ok了,静态方法,成员方法,构造方法都是方法,只要是方法就去试试。
Lamda表达式的学习就到这里了,希望这篇文章能够帮助到一些小伙伴。求真至善,登崇俊良。我们下一期再见。