匿名内部类
new Swim() {
@override
public void swim() {
...
}
}
这段代码得到了一个实现了Swim接口的类的对象
常用该对象作为一些方法的参数
比如TreeSet的有参构造中需要传入的比较器对象
TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
...
}
});
lambda表达式
承然,使用匿名内部类已经简化了参数的传递,不然,需要另创建一个类实现接口,重写方法,并new一个对象再传递。
但如果要实现的接口是函数式接口,即接口有@FunctionalInterface注解,要求该接口有且仅有一个抽象方法
我们就可以用lambda表达式进一步简化
// 可以ctrl+b查看Comparator,可以看到有@FunctionalInterface注解,
// 即comparator接口有且只有一个抽象方法
// 故可用lambda表达式简化匿名内部类的写法
TreeSet<Teacher> ts = new TreeSet<>((o1, o2) -> {
...
});
lambda表达式形似js中箭头函数的形式,这里表示的是一个接口的实现类对象
因为该接口只有一个抽象方法,故可以用这样一个“函数”表示这个接口,
实际上lambda表达式表示的就是这个唯一的抽象方法
lambda表达式简写规则
- 参数类型可以不写
- 只有一个参数()可以不写
- 函数体只有一行可以不用写{},默认编译为 return 这一行
方法引用
某些情况还可以使用方法引用,避免逻辑的重复书写,使更加简洁
- 方法引用符
:: 该符号为引用运算符,而它所在的表达式被称为方法引用 - 推导与省略
- 如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导
- 如果使用方法引用,也是同样可以根据上下文进行推导
方法引用分为,引用类方法,引用对象的实例方法,引用类的实例方法和引用构造器
- 引用类方法
public interface Converter {
int convert(String s);
}
public class ConverterDemo {
public static void main(String[] args) {
//Lambda写法
useConverter(s -> Integer.parseInt(s));
//引用类方法
useConverter(Integer::parseInt);
}
private static void useConverter(Converter c) {
int number = c.convert("666");
System.out.println(number);
}
}
引用类方法,引用的是类的静态方法
AClass::fun表示用 T Aclass.fun(args)函数代表一个函数式接口的实现类对象
参数和返回值必须和要实现的接口中的抽象方法对应
- 引用对象的实例方法
public class PrintString {
//把字符串参数变成大写的数据,然后在控制台输出
public void printUpper(String s) {
String result = s.toUpperCase();
System.out.println(result);
}
}
public interface Printer {
void printUpperCase(String s);
}
public class PrinterDemo {
public static void main(String[] args) {
//Lambda简化写法
usePrinter(s -> System.out.println(s.toUpperCase()));
//引用对象的实例方法
PrintString ps = new PrintString();
usePrinter(ps::printUpper);
}
private static void usePrinter(Printer p) {
p.printUpperCase("HelloWorld");
}
}
引用对象的实例方法
obj::fun 表示用 实例obj的fun方法代表一个函数式接口的实现类对象
参数和返回值必须和要实现的接口中的抽象方法对应
- 引用类的实例方法
public interface MyString {
String mySubString(String s,int x,int y);
}
public class MyStringDemo {
public static void main(String[] args) {
//Lambda简化写法
useMyString((s,x,y) -> s.substring(x,y));
//引用类的实例方法
useMyString(String::substring);
}
private static void useMyString(MyString my) {
String s = my.mySubString("HelloWorld", 2, 5);
System.out.println(s);
}
}
引用类的实例方法,引用类的非静态方法
要求该类是接口的抽象方法中的第一个参数类型,后面参数依次对应
如用String::substring表示一个函数式接口的实现类对象
该接口的抽象方法需满足,传入的参数分别是String,int,int,返回值为String
- 引用构造器
public class Student {
private String name;
private int age;
public Student() {
}
public Student(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;
}
}
public interface StudentBuilder {
Student build(String name,int age);
}
public class StudentDemo {
public static void main(String[] args) {
//Lambda简化写法
useStudentBuilder((name,age) -> new Student(name,age));
//引用构造器
useStudentBuilder(Student::new);
}
private static void useStudentBuilder(StudentBuilder sb) {
Student s = sb.build("林青霞", 30);
System.out.println(s.getName() + "," + s.getAge());
}
}
引用构造器,引用类的构造方法
如用Student::new表示一个函数式接口的实现类对象
那么该接口的抽象方法应满足,返回值为Student,
对参数的要求是,能在Student的构造方法中能找到一个参数列表相同的