Java基础25–Lambda表达式
Java8于2014年3月14日发布,可以看成是自Java5以来最具革命性的版本。虽然有很多新的版本,但企业里还是用Java8比较多
Java5新特性:
1:可变参数...
2:枚举
3:注解
4:泛型
5:foreach
.......
Java8新特性:
1:接口:默认方法和静态方法
2:日期时间API
3:Lambda表达式
4:StreamAPI
5:Optional类
.....
Lambda表达式演示
Lambda表达式是函数式编程的风格,是为了给SAM接口(唯一的抽象方法)的变量和形参赋值的一种语法。很多语言都支持Lambda表达式,比如Java、c、c++
目的:减少代码的冗余,增加可读性。
示例1:
开启一个线程,这个线程的任务:打印“hello”
要求用实现Runnable接口的方式来创建多线程
@Test
public void test01(){
// 非Lambda表达式方式实现,并且有名字的实现类实现
MyRunnable my = new MyRunnable();
Thread t = new Thread(my);
t.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("hello");
}
改成匿名的内部类实现,有对象名字
@Test
public void test02(){
//匿名内部类,对象有名字
Runnable my = new Runnable(){
@Override
public void run() {
System.out.println("hello");
}
};
Thread t = new Thread(my);
t.start();
}
匿名内部类,匿名对象
@Test
public void test03(){
//匿名内部类,匿名对象
Thread t = new Thread(new Runnable(){
@Override
public void run() {
System.out.println("hello");
}
});
t.start();
}
//或者写为
@Test
public void test04(){
//匿名内部类,匿名对象
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("hello");
}
}).start();
}
使用Lambda实现。
Runnable接口符合SAM特征: public abstract void run();
@Test
public void test05(){
//使用Lambda表达式
new Thread(()->System.out.println("hello")).start();
}
//很简洁
//因为Runnable接口符合SAM特征: public abstract void run();所以可以省略
示例二:
有一个数组,存储了5个学生对象,这个学生类的自然排序是按照编号排序。但是我希望这个数组是按照姓名排序
Comparator符合SAM接口的特征: public abstract int compare(T t1, T t2)
class Student implements Comparable<Student>{
private int id;
private String name;
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Student() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
@Override
public int compareTo(Student o) {
return this.id - o.id;
}
}
@Test
public void test01(){
Student[] arr = new Student[5];
arr[0] = new Student(1,"zhangsan");
arr[1] = new Student(2,"lisi");
arr[2] = new Student(3,"wangwu");
arr[3] = new Student(4,"zhaoliu");
arr[4] = new Student(5,"qianqi");
Arrays.sort(arr);//按照元素的自然顺序排列
for (Student student : arr) {
System.out.println(student);
}
}
以上代码是自然排序按照编号排序,
按照姓名排序(需要定制排序)
class NameComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getName().compareTo(o2.getName());
}
}
@Test
public void test02(){
Student[] arr = new Student[5];
arr[0] = new Student(1,"zhangsan");
arr[1] = new Student(2,"lisi");
arr[2] = new Student(3,"wangwu");
arr[3] = new Student(4,"zhaoliu");
arr[4] = new Student(5,"qianqi");
Arrays.sort(arr, new NameComparator());//按照元素的姓名定制排序
for (Student student : arr) {
System.out.println(student);
}
}
改为匿名内部类实现
@Test
public void test03(){
Student[] arr = new Student[5];
arr[0] = new Student(1,"zhangsan");
arr[1] = new Student(2,"lisi");
arr[2] = new Student(3,"wangwu");
arr[3] = new Student(4,"zhaoliu");
arr[4] = new Student(5,"qianqi");
Arrays.sort(arr, new Comparator<Student>(){
@Override
public int compare(Student o1, Student o2) {
return o1.getName().compareTo(o2.getName());
}
});//按照元素的姓名定制排序
for (Student student : arr) {
System.out.println(student);
}
}
改为Lambda实现
@Test
public void test04(){
Student[] arr = new Student[5];
arr[0] = new Student(1,"zhangsan");
arr[1] = new Student(2,"lisi");
arr[2] = new Student(3,"wangwu");
arr[3] = new Student(4,"zhaoliu");
arr[4] = new Student(5,"qianqi");
Arrays.sort(arr, (o1, o2)-> o1.getName().compareTo(o2.getName()));//按照元素的姓名定制排序
for (Student student : arr) {
System.out.println(student);
}
}
代码更简洁
函数式接口:SAM接口
Lambda表达式是对匿名内部类的简化,且匿名内部类是实现SAM的接口的匿名内部类才行
函数式接口:SAM接口
Single Abstract Method,即该接口中只有一个抽象方法需要实现,当然该接口可以包含其他非抽象方法(默认方法和静态方法,或者是从Object继承的方法)。
回忆之前学过的接口:
(1)Runnable
(2)Comparable
(3)Comparator
(4)Iterable
(5)Iterator
(6)Collection,Set,List,Map,Queue,Deque…
(7)Serializable
(8)Externalizable
(9)FileFilter
(10)InvocationHandler
…
哪些是符号SAM特征的呢?
(1)Runnable public void run()
(2)Comparable public int compareTo(T t)
(3)Comparator public int compare(T t1, T t2)
(4)Iterable public Iterator iterator()
(5)FileFilter public boolean accept(File pathname);
(6)InvocationHandler public Object invoke(Object proxy, Method method, Object[] args)
按照语法来说,只要符号SAM特征的接口,都可以使用Lambda表达式。
但是Java建议只针对标记了@FunctionalInterface这注解的SAM接口使用Lambda表达式
上面哪些标记了@FunctionalInterface注解:
(1)Runnable public void run()
(3)Comparator public int compare(T t1, T t2)
(5)FileFilter public boolean accept(File pathname);
如果没有标记@FunctionalInterface注解的,说明它考虑了以后可能增加抽象方法。目前使用没问题,就是以后可能有风险。