本人小白一枚,欢迎大家一起讨论学习,如有错误,还望大家指教。
简述:
我们都知道,java是一门面向对象的编程语言,它强调的是当我们做一件事时,找一个能解决这个事物的对象,通过调用这个对象来解决这个事物。面向对象过分强调了必须通过对象的形式来完成事物,而在这里我们引入另一种思想,这就是函数式编程思想,函数在数学中就是有输入、输出的一套计算方案,函数式编程强调的是做什么,而不是以什么形式去做。即只要能获得结果,谁去做的,怎么做的都不重要,重视的是结果,而不是过程。这种思想是在2014年3月份Oracle公司所发布的java 8(JDK1.8)中提出的,在其加入了Lambda表达式这种重量级新特征,为我们打开了新世界的大门。
分析:
传统写法:
当我们需要启动一个线程去完成某些任务时,我们通常会用实现 java.lang.Runnable
接口的方式来完成,并使用java.lang.Thread
类来启动线程。代码如下:
class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":开始执行了!");
}
}
public class LambdaDemo2 {
public static void main(String[] args) {
RunnableImpl runnable = new RunnableImpl();
Thread thread = new Thread(runnable);
// 启动线程
thread.start();
// 使用匿名内部类,调用方法链简化写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":开始执行了!");
}
}).start();
}
}
分析: 对于使用匿名内部类的用法,可以分析一下几点内容。
Thread
类需要Runnable
接口作为参数,其中的抽象run
方法是线程任务内容的核心。- 为了指定
run
方法体,我们不得不需要Runnable
接口的实现类。 - 为了省去定义
Runnable
实现类的繁琐,不得不使用匿名内部类。 - 并且必须覆盖重写
run
方法,方法名称、方法参数、方法返回值不得不再写一遍,且不能书写错误。 - 然而,似乎只有方法体才是关键所在。
Lambda写法:
public static void main(String[] args) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + ":开始执行了");
}).start();
}
这段代码和上述代码功能完全一致,可以在JDK1.8或更高版本下编译运行。从中我们不难看出,这种写法更加简洁,不再有不得不创建接口对象的束缚以及不再有抽象方法覆盖重写的负担。
Lambda标准格式:
Lambda标准格式有3个部分组成:
- 参数列表
- 指向箭头
- 执行代码
写法:(参数类型 参数名称) ‐> { 代码语句 }
格式说明:
- 小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
- ‐> 是新引入的语法格式,代表参数传递指向。
- 大括号代表抽象方法的方法体。
Lambda省略格式:
Lambda表达式强调的是“做什么”,而不是“以什么形式去做”。所以凡是可以根据上下文推导的信息我们都可省略。
省略规则:在Lambda标准格式的基础上,使用省略写法的规则如下
- 小括号内参数的类型可以省略。
- 如果小括号内有且只有一个参数,则小括号可以省略。
- 如果大括号内有且只有一个语句,则无论是否有返回值,都可以省略大括号、return关键字以及语句分号。
Lambda的使用前提:
Lambda表达式的语法非常简洁,完全没有面向对象复杂的束缚,但是Lambda表达式使用有几个条件:
- 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法,这样的接口称为函数式接口,可以用注解
@FunctionalInterface
标记。 - 使用Lambda必须具有上下文推断。也就是方法的参数或局部变量的类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
举例:
对Person数组中的元素以年龄的大小进行排序,在这里使用Arrays.sort方法,此方法需要一个Comparator接口实例来指定排序的规则。
public class LambdaDemo {
public static void main(String[] args) {
Person[] persons = new Person[] {
new Person("张三", 23),
new Person("李四", 18),
new Person("王五", 15),
new Person("刘六", 28)
};
// lambda写法,这里使用lambda省略写法
// Arrays.sort(persons, (p1, p2) -> p1.getAge() - p2.getAge());
Arrays.sort(persons, new Comparator<Person>() {
@Override
public int compare(Person person1, Person person2) {
return person1.getAge() - person2.getAge();
}
});
for(int i = 0;i < persons.length;i++) {
System.out.println(persons[i]);
}
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Person{name=‘王五’, age=15}
Person{name=‘李四’, age=18}
Person{name=‘张三’, age=23}
Person{name=‘刘六’, age=28}
通过上例可知,如果方法的参数是一个函数式接口类型,那么就可以使用Lambda表达式进行替代,如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式。
private static Comparator<Person> newComparator() {
return (p1, p2) -> p1.getAge() - p2.getAge();
}