Java8新特性—Lambda表达式与函数式编程

版权声明:本文为神州灵云作者的原创文章,未经神州灵云允许不得转载。

本文作者:Rujion

在JDK8之前,我们常会使用匿名类来表示一些的代码块,从外部传递方法,但是十分繁琐。在JDK8中,出现了一个新的工具Lambda表达式,同时也引进了一种新的编程方式——函数式编程。

##1.什么是函数式编程

在聊Lambda表达式之前,先聊聊函数式编程。
函数式编程是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。
简单的说,函数式编程更强调的是函数的计算,这使得它方便理解,灵活性更高。函数式编程有几个鲜明的特性:

a)函数是"第一等公民"
“第一等公民”表示函数和其他数据类型一样,可以赋值给变量,可以作为参数或返回值

b)没有"副作用":
所谓"副作用",指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。
函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。

c)不修改状态
与上条类似,函数式编程只返回新的值,而不改变变量,

d)引用透明性
即对于相同的输入,函数总是返回相同的结果,也就是说函数表达式是纯粹的,不依赖于其他全局变量或计算顺序等。

相对其他编程方式,函数式编程有着其独特的优势,首先由于其关注计算本身的特点,函数式编程的代码往往比较简洁,同时也利于理解。同时,由于它不依赖于外部,所以方便单元测试与除错。同时由于函数式编程不改变变量,所以他易于并发编程,因为不改变变量,所以线程间不会互相干预或抢占锁。

##2.什么是Lambda表达式:

举个例子:
之前我们对集合进行排序可能是这样的:

List list = new ArrayList<>();

list.sort(new Comparator() {
   @Override
   public int compare(Integer o1, Integer o2) {
      return o1.compareTo(o2);
   }
});

使用Lambda表达式后:
List list = new ArrayList<>();

list.sort((o1, o2) -> o1.compareTo(o2));
是不是显得十分简单易懂。
Lambda表达式通用形式如下:

		(parameter1, parameter2,.....) -> {
statsment1
statsment2
......
return ...;
}

即形参 -> 表达式/方法体。
对于单个参数,也可以简化为:

		parameter -> {
statsment1
statsment2
......
return ...;
}

对于单个语句,可简化为:
parameter -> stasment
对于函数引用:
1)静态方法引用:
args -> StaticClass.method(args) 等价于 StaticClass :: method
2)实例方法引用:
(args) -> inst.method(args) 等价于 inst :: method
3)对象方法引用:
(inst, args) –> inst.method(args) 等价于 StaticClass :: method
4)构造方法引用:
x->new Class(x) 等价于 Class :: new

##3. Lambda表达式的实现
Lambda表达式其实是Java8对接口实现类的另一方式,避免了代码中的匿名类,但是这也是有一定条件的,这一接口必须是函数式接口 —— 只有一个抽象方法的接口,可以通过 @FunctionalInterface 来修饰。
为了便于开发,Java8 还提供了一些内置接口,方便直接重写。

  1. Consumer 对类型为T的对象应用操作,没有返回值
  2. Supplier 返回类型为T的对象
  3. Function 对类型为T的对象应用操作并返回R类型的对象。
  4. Predicate 确定类型为T的对象是否满足约束,返回值为boolean型。

##4. Lambda表达式的使用
来举个例子:

public class Student {
    private int age;
    private String name;
    private int id;
}

用最简单的排序做个例子:
List students = new ArrayList<>();
students.sort((std1, std2) -> std1.getAge() - std2.getAge());

进一步的可以使用Comparator内置的方法
List students = new ArrayList<>();
students.sort(Comparator.comparingInt(Student::getAge));
我们可以将这一Comparator存为静态变量方便调用

public class Student {
    private int age;
    private String name;
    private int id;

    public static Comparator BYAGE = Comparator.comparingInt(Student::getAge);
    public static Comparator BYNAME = Comparator.comparing(Student::getName);
    public static Comparator BYID = Comparator.comparingInt(Student::getId);
	}

有时候我们需要对多个字段排序,按照以前的方法,我们可能要多些一个方法或匿名类来进行新的排序,但是使用Lambda表达式,我们就可以复用已经写好的

Comparator。
List students = new ArrayList<>();
students.sort(Student.BYAGE
            .thenComparing(Student.BYNAME));

当然,Lambda表达式还有一个重要的使用场景 —— Stream,Stream让我们能非常方便高效的对集合进行各种操作。
例如:
List students = new ArrayList<>();
List nameList = students.stream()
.sorted(Student.BYAGE)
.map(Student::getName)
.collect(Collectors.toList());

很方便的就取出了按年龄排序后学生的名称列表,而且方便代码阅读与理解,当然Stream结合Lambda表达式还有许多使用方法,这里不一一叙述了,可以看到,Lambda表达式大大精简了代码量,同时也使代码便于理解与复用。

##5. Lambda表达式使用注意

  1. Lambda表达式中的this 表示的是表达式声明的外部对象,而不是Lambda表达式操作的对象
  2. Lambda表达式引用外部对象时,由于其不改变外部变量的值,会默认加上final标签,所以在Lambda内部是无法改变外部变量的值。
  3. Lambda 表达式是惰性计算的,只有在代码真正执行时才会进行求解计算,利用这一特性可以实现无限输出等特殊功能。

##6.总结

Lambda 的出现为Java带来了函数式编程的新编程方式,使得我们可以用更简洁易懂的代码实现更复杂,更灵活的功能。相信这一新特性也能为代码复用,解耦合带来不少的方便,学习与使用Lambda表达式能为我们的编程带来提高。

Java8新特性—Lambda表达式与函数式编程_第1张图片

你可能感兴趣的:(Java8新特性—Lambda表达式与函数式编程)