目录
一、前言
Lambda表达式是Java8中最瞩目的新特性之一,Lambda表达式描述的是一个代码块或者称为匿名方法,可以将其作为参数传递给构造方法和或者普通方法以便后续执行。为了简便代码块的使用,最直观的应该就是简化匿名内部类的使用。
二、Lambda表达式语法
体验一下:A是一个接口,还有一个add方法,B是一个实体类,需求是B需要实现调用A的方法,N多年的实现方式可以通过实现这个类而重写这个方法或者通过匿名内部类,现在只需要通过Lambda表达式的三行代码就可以完成实现这个需求,Lambda表达式的简洁语法一定会给你留下深刻的印象。
A接口
public interface A {
public abstract void add();
}
B类
public class B {
public B(A a){
}
}
测试类
public static void main(String[] args) {
//1.Lambda
new B(() -> {
System.out.print("Lambda1");
});
//2.匿名内部类
new B(new A() {
@Override
public void add() {
System.out.print("anonymous");
}
});
}
Lambda使用的一个重要依据必须存在函数接口,上面的例子只是无参的一种写法,Lambda表达式的编写方法还有很多种:
无参函数的写法
无参表达式:
1.当只有一行计算的计算的时候Lambda可以无需大括号{}
例:
() -> System.out.print("Lambda1" + "\n");
(),-> 表达式
2.当计算方法无法房子一个表达式时可以将代码块放在{}中
例:
() -> {
System.out.print("Lambda1" + "\n");
System.out.print("Lambda2" + "\n");
};
示例:
public static void main(String[] args) {
//Java1.8以前的写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Java1.7");
}
}).start();
//Java1.8 Lambda表达式
new Thread(() ->System.out.print("Runnable")).start();
}
含参表达式:
上面的类子只是无参的一种写法,Lambda表达式的编写方法还有很多种:
含参函数:
一、单个参数
(参数类型 参数)-> 表达式
1.表达式
(String a) -> System.out.print(a);
2.代码块
(String a) ->{
System.out.print(a)
System.out.print(a)
};
Labbda表达式可以根据上下文推断出参数类型,所以还可以省去参数类型(不建议这种编写方式,使代码的可读性差)
(参数)-> 表达式
(a) -> System.out.print(a);
二、多个参数
(参数类型1 参数1,参数类型2,参数2)-> 表达式
(String a,String b) ->{
System.out.print(a)
System.out.print(b)
};
当多参函数只有一条表示式时也可以简写:
(String a,String b) -> System.out.print(a+b);
Lambda表达式甚至还可以省略参数:
(引用类型::函数方法)
示例:
//Comparator接口
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
//安装从大到下排序集合的元素
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(3, 1, 2);
List<Integer> list2 = Arrays.asList(1, 3, 2);
List<Integer> list3 = Arrays.asList(3, 2, 1);
//Java1.8之前的写法
Collections.sort(list1, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
System.out.print(list1 + "\n");
//Lambda表达式
Collections.sort(list2, (Integer o1, Integer o2) -> {
return o1.compareTo(o2);
});
//还可以把参数类型和return省略
Collections.sort(list2, (o1,o2)->o1.compareTo(o2));
System.out.print(list2 + "\n");
//Lambda表达式更简化的写法,省略参数
Collections.sort(list3, Integer::compareTo);
System.out.print(list3);
}
打印结果:
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
关于变量:
- Lambda表达式中的变量是最终变量,在变量初始化之后就不会再为它赋新值,而如果变量是动态可变的,将不被允许(比如for循环中i);
- 因为Lambda表达式和匿名内部类作用域是一样的,所有不能有同名的局部变量;
- 在This关键字是指的当前类,而不是函数接口;
三、Lambda表达式的语法糖
在Lamdba的的梳理方法中,看到了(引用类型::函数方法)的写法,可能都会这种语法比较疑惑,这种写法其实是Java的一个语法糖,有时已经可能有线程的方法可以完成传递代码的工作,这种语法糖的编写方式使代码变得更加简洁,对于引用的方法,主要有四种:
- 对象方法
- 静态方法
- 类方法
- 构造器
引用对象方法:
当调用表达式可以通过对象引用::对象方法d的方式表示:
语法:
对象引用::对象方法
示例:
//接口
interface MethodRef{
void test(int b);
}
public class Test01 {
public static void main(String[] args) {
//传统内部类
MethodRef mr1 = new MethodRef() {
@Override
public void test(String s1) {
System.out.println(s1);
}
};
mr1.test("传统内部类");
//Lambda传统写法
MethodRef mr2 =(s2) -> System.out.println(s2);
mr2.test("Lambda传统写法");
//Lambad引用对象方法
MethodRef mr3 = System.out::println;
mr3.test("Lambad引用对象方法");
}
}
输出:
传统内部类
Lambda传统写法
Lambad引用对象方法
-----------------------------------------------------------
System.out对应的是PrintStream
当调用本身类方法是对象引用还是修改为this
引用静态方法:
当调用方法为静态方法时,可以使用 类名::静态方法的方式
语法:
类名::静态方法
示例:
//实现工具类
public class Until {
public static int comare(Integer a,Integer b){
return a.compareTo(b);
}
}
//测试类
public class Test02 {
public static void main(String[] args) {
//静态方法引用
List<Integer> list1 = Arrays.asList(3, 1, 2);
Collections.sort(list1, Until::comare);
System.out.print(list1);
}
}
输出:
[1, 2, 3]
类方法引用:
当存在多个参数,且调用的方法是是第一个参数的实例方法,并且以后的参数能对应该方法的参数列表,那么还有一种更直接的方式
语法:
类名::实例方法名
interface MethodRef2 {
void test(String s1, String s2);
}
public static void main(String[] args) {
//传统内部类
MethodRef2 mr1 = new MethodRef2() {
@Override
public void test(String s1, String s2) {
s1.compareToIgnoreCase(s2);
}
};
mr1.test("a", "b");
//Lambda传统写法
MethodRef2 mr2 = (s1, s2) -> s1.compareToIgnoreCase(s2);
mr2.test("1", "2");
//Lambad引用类方法
MethodRef2 mr3 = String::compareToIgnoreCase;
mr3.test("1", "2");
}
}
构造器引用:
调用构造器
语法:
type ::new
//接口
interface MethodRef3 {
F test(String str);
}
//F类
public class F {
public F(String str){
System.out.println(str);
}
}
//测试类
public class Test03 {
public static void main(String[] args) {
//传承内部类
MethodRef3 mr1 = new MethodRef3() {
@Override
public F test(String str) {
return new F(str);
}
};
mr1.test("传承内部类初始化");
//lambda简化写法
MethodRef3 ms2 = F::new;
F f = ms2.test("lambda简化写法初使化");
//lambda传统写法
MethodRef3 mr3 = (str) -> new F(str);
mr3.test("lambda传统写法初始化");
}
}
在经过初步了解了Lambda的使用方法之后,Lambda简化了编程步骤,但是代码风格的转变和差异,也会让很多不了解的Lambda的表达式的对代码的不理解。其实最初的学习前期,可以通过类比Lambda和匿名内部类来加深印象。
四、初步了解函数式接口:
对于只有一个抽象方法的接口,我们称为函数式接口(functional interface),当然部分接口也隐含着Object的公共方法。Java中提供了很多分装代码块的接口,如Comparator和Runnable。lambda表达式与这些接口都是兼容的。Java8中已经定义了很多常用的函数式接口,它们都放在java.util.function包下面,一般有以下常用的四大核心接口:
以上就是对Lambda表达式的一些最基础的了解,后续会针对函数式接口的实际应用再来学习学习。