1、Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口(只包含一个抽象方法的接口 )。 请观察如下代码,并使用Lambda表达式改写,实现相同的效果。
// 使用匿名内部类的方式实现多线程
Runnable runnable1 = new Runnable() {
public void run() {
System.out.println(“do something…”);
}
}
public static void main(String[] args) {
new Thread(() -> System.out.println("do something...")).start();
}
2、请观察如下代码,其实现的效果是将数组中的元素按照从大到小的顺序排序:
public class Test {
public static void main(String[] args) {
Integer[] arr = {2, 4, 6, 1, 9, 3, 0, 7};
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Integer i1, Integer i2) {
return i2.compareTo(i1);
}
});
System.out.println(Arrays.toString(arr));
}
}
请使用Lambda表达式,改写以上代码,实现相同的需求。
public static void main(String[] args) {
Integer[] arr = {2, 4, 6, 1, 9, 3, 0, 7};
Arrays.sort(arr,(i1,i2) ->i2.compareTo(i1));
System.out.println(Arrays.toString(arr));
}
3、方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。 请阅读如下代码:
class Student {
private String name;
private Integer age;
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
// 省略 getters and setters
// 比较两个学生对象年龄的方法
public static int compareByAge(Student s1, Student s2) {
return s1.age.compareTo(s2.age);
}
}
假设我们现在有一个Student对象数组,要按照学生的年龄从小到大排序:
public class Test {
public static void main(String[] args) {
Student[] students = {
new Student(“Tom”, 20),
new Student(“Jerry”, 18),
new Student(“Lily”, 19),
new Student(“Lucy”, 22),
new Student(“kevin”, 21)};
// 使用匿名内部类
/*
Arrays.sort(students, new Comparator() {
@Override
public int compare(Student s1, Student s2) {
return s1.getAge().compareTo(s2.getAge());
}
});
*/
// 第一步,使用Lambda表达式改写
// 第二步,使用方法引用改写
// 遍历
for (Student student : students) {
System.out.println(student.getName() + " - " + student.getAge());
}
}
}
我们可以使用匿名内部类的方式,传递Comparator的子类对象,实现排序。而Comparator是一个函数式接口,请先使用Lambda表达式改写中间被注释的排序代码,实现相同的需求。 然后我们还发现,关于两个年龄的比较方法,已经在Student类中实现了,因此,我们可以直接使用已存在的Student.compareByAge方法,请继续采用方法引用的方式改写排序代码,实现相同的需求。
学生类:
public class Student {
private String name;
private Integer age;
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public static int compareByAge(Student s1, Student s2) {
return s1.age.compareTo(s2.age);
}
}
测试类:
public static void main(String[] args) {
Student[] students = {
new Student("Tom", 20),
new Student("Jerry", 18),
new Student("Lily", 19),
new Student("Lucy", 22),
new Student("kevin", 21)};
Arrays.sort(students, Comparator.comparing(Student::getAge));
for (Student student : students) {
System.out.println(student.getName() + " - " + student.getAge());
}
}
4、静态方法的引用,组成语法格式:ClassName::staticMethodName 例如: String::valueOf 等价于lambda表达式 (s) -> String.valueOf(s) 请阅读如下材料:
public class Test {
public static void main(String[] args) {
String str = “this is a function reference test”;
// 调用方法,获取反转的结果
/*
String revStr = StringOperate(new StringInter(){
@Override
public String func(String str) {
return new StringBuilder(str).reverse().toString();
}
}, str);
*/
// 请使用方法引用改写
System.out.println("str: " + str);
System.out.println("revStr: " + revStr);
}
// 在主方法中调用该方法,得到反转的字符串
public static String StringOperate(StringInter si, String str) {
return si.func(str);
}
}
// 函数式接口
interface StringInter {
String func(String str);
}
// 一个字符串操作类
class MyStringOps {
// 反转字符串的静态方法
public static String strReverse(String str) {
return new StringBuilder(str).reverse().toString();
}
}
假设有一个函数式接口StringInter,在测试类中,有一个方法StringOperate,要求在主方法中调用StringOperate方法,可以获取反转后的字符串,我们同样可以采用匿名内部类的方式实现这个接口,但材料中已经有一个字符串操作类实现了这个功能,请使用方法引用改进注释掉的代码部分,实现需求。
public class MyStringOps {
public static String strReverse(String str) {
return new StringBuilder(str).reverse().toString();
}
}
public interface StringInter {
String func(String str);
}
public static void main(String[] args) {
String str = "this is a function reference test";
String revStr = StringOperate(str1 -> new StringBuilder(str1).reverse().toString(), str);
System.out.println("str: " + str);
System.out.println("revStr: " + revStr);
}
public static String StringOperate(StringInter si, String str) {
return si.func(str);
}
5、构造方法引用(也可以称作构造器引用),组成语法格式:Class::new 例如: String::new, 等价于lambda表达式 () -> new String() 请阅读如下材料:
public class Test {
public static void main(String[] args) {
// 使用匿名内部类
/*
MyInter mi = new MyInter() {
@Override
public MyClass func(int value) {
return new MyClass(value);
}
};
MyClass mc = mi.func(100);
*/
// 使用Lambda表达式改进
// 使用方法引用改进
// 打印成员变量的值
System.out.println(mc.getValue());
}
}
// 函数式接口
interface MyInter {
MyClass func(int value);
}
class MyClass {
private int value;
// 构造方法
public MyClass(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
函数式接口MyInter中提供了一个返回MyClass对象的抽象方法,在测试类中,需要调用该方法获取到MyClass的对象,使用匿名内部类的方式以及给出,请分别使用Lambda表达式和方法引用的方式改进注释部分的代码。
public class MyClass {
private int value;
public MyClass(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
public interface MyInter {
MyClass func(int value);
}
public static void main(String[] args) {
// 使用匿名内部类
MyInter mi = new MyInter() {
@Override
public MyClass func(int value) {
return new MyClass(value);
}
};
MyClass mc = mi.func(100);
// 使用Lambda表达式改进
MyInter mi1 = value -> new MyClass(value);
MyClass mc1 = mi1.func(100);
// 使用方法引用改进
MyInter mi2 = MyClass::new;
MyClass mc2 = mi2.func(100);
// 打印成员变量的值
System.out.println(mc.getValue());
System.out.println(mc1.getValue());
System.out.println(mc2.getValue());
}