一.函数式编程思想
- 面向对象思想主要是关注对象能完成什么事情,函数式编程思想就像函数式,主要是针对数据操作;
- 代码简洁容易理解,方便于并发编程,不需要过分关注线程安全问题
二.lambda表达式
1.概念
lambda表达式是Java8的一个新特性,从本质上来讲是一个匿名函数,可以使用这个匿名函数实现接口中的方法,并且非常简洁。
通常来讲,使用 lambda表达式 是为了简化接口实现的。关于接口实现,可以有很多种方式来实现。例如L设计接口的实现类、使用匿名内部类。但是lambda表达式比这两种方式都简单。可以把lambda看成JDK8中的一个语法糖。
2.Lambda表达式对接口的要求
并不是所有的接口都可以使用lambda表达式来简洁实现的。lambda表达式毕竟只是一个匿名方法。当实现的接口中的方法过多或者过少的时候,lambda表达式都是不适用的。
lambda表达式只能实现函数式接口。即一个接口中,要求实现类必须实现的抽象方法,有且只有一个,这样的接口就是函数式接口。
3.Lambda表达式的语法
(参数)->{方法体}
- 参数部分︰方法的参数列表,要求和实现的接口中的方法参数部分一致,包括参数的数量和类型。
- 方法体部分∶方法的实现部分,如果接口中定义的方法有返回值,则在实现的时候,注意返回值的返回。
- ->:分隔参数部分和方法体部分。
- 因为接口中规定了方法参数类型,所以实际写lambda表达式的时候可以省略 参数类型。如果只有一个参数,可以省略()
- 另外如果方法体里只有一个语句,那么可以省略掉 {},如果该语句是return语句,需要把return也省略掉
省略如下:
4.函数引用
lambda表达式是为了简化接口的实现的。在lambda表达式中,不应该出现比较复杂的逻辑。如果在lambda表达式中出现了过于复杂的逻辑,会对程序的可读性造成非常大的影响。
如果在lambda表达式中需要处理的逻辑比较复杂,一般情况会单独的写一个方法。在lambda表达式中直接引用这个方法即可。或者,在有些情况下,我们需要在lambda表达式中实现的逻辑,在另外一个地方已经写好了。此时我们就不需要再单独写一遍,只需要直接引用这个已经存在的方法即可。
函数引用:引用一个已经存在的方法,使其替代lambda表达式完成接口的实现。
4.1引用一个静态方法
接口依然是上面的MultipleParametersReturn,引用如下
需要注意的是引用的 方法的参数 和 返回值类型 要与 接口 对应
4.2引用一个非静态方法
4.3引用构造方法
Person类
public class Person {
private Integer age;
private String name;
public Person() {
}
public Person(Integer age) {
this.age = age;
}
public Person(Integer age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
PersonWithNoParam接口
@FunctionalInterface
public interface PersonWithNoParam {
Person getPersonWithNoParam();
}
PersonWithOneParam接口
@FunctionalInterface
public interface PersonWithOneParam {
Person getPersonWithOneParam(Integer age);
}
PersonWithDoubleParams接口
@FunctionalInterface
public interface PersonWithDoubleParams {
Person getPersonWithDoubleParams(Integer age,String name);
}
Demo
public class Demo1 {
public static void main(String[] args) {
//lambda表达式实现PersonWithNoParam接口
PersonWithNoParam t1=Person::new;//无参构造函数引用
System.out.println(t1.getPersonWithNoParam());
//lambda表达式实现PersonWithOneParam接口
PersonWithOneParam t2=Person::new;//单参构造函数引用
System.out.println(t2.getPersonWithOneParam(10));
//lambda表达式实现PersonWithDoubleParams接口
PersonWithDoubleParams t3=Person::new;//多参构造函数引用
System.out.println(t3.getPersonWithDoubleParams(10,"小王"));
}
}
lambda表达式会自动根据 方法的参数类型 匹配Person类中对应的构造方法
5.特殊的函数引用
如果在使用lambda表达式实现某些接口的时候,lambda表达式的参数列表中包含了某一个对象,此时方法体中,直接使用这个对象调用它的某一个方法就可以完成整体的逻辑,并且其他的参数可以作为调用方法的参数。此时,可以对这种实现进行简化。
Person类
public class Person {
private Integer age;
private String name;
public Person() {
}
public Person(Integer age) {
this.age = age;
}
public Person(Integer age, String name) {
this.age = age;
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
PersonSpecial接口
public interface PersonSpecial {
void setAge (Person person,Integer age);
}
Demo2
public class Demo2 {
public static void main(String[] args) {
//简化前
PersonSpecial t=(person,age)->person.setAge(age);
//用对象的特殊引用简化后
PersonSpecial t2=Person::setAge;
Person person = new Person();
t2.setAge(person,13);
System.out.println(person);
}
}
6.闭包
如果某一个局部变量被用在了某一个代码块中,这其实就形成了对这个局部变量的包围,我们称"闭包"。这个时候这个变量不允许被改变,即final
如下编译器会报错:
如果使用的是全局变量则不会出现闭包问题
三.Stream流
Java8的 使用的是函数式编程模式,可以被用来对集合或数组进行链状流式的操作。有别于IO流,这里是针对集合操作数据的流