这两天看到Java8的新特性,发现真的好用,代码更加简洁了,看着就舒服,所以我不得不在这里记录一下
以下详细介绍不按照上面顺序排列,自行看大标题区分
方法引用
这是Java8出来之前调用isHidden方法的语句
File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isHidden();
}
});
看起来虽热只有三行,但是逻辑有点绕,然后变成Lambda表达式
File[] hiddenFiles = new File(".").listFiles(file -> file.isHidden());
用方法引用会更简略
File[] hiddenFiles = new File(".").listFiles(File::isHidden);
哈哈,是不是看起来逻辑很明了,也很简洁?
在Java 8里写下File::isHidden的时候,你就创建了一个方法引用,你同样可以传递它。只要方法中有代码(方法中的可执行部分),那么用方法引用就可以传递代码。
Lambda——匿名函数
使用匿名类来表示不同的行为并不令人满意:代码十分啰嗦,这会影响程序员在实践中使用行为参数化的积极性。Lambda(最初是根据希腊字母λ命名的。虽然Java中不使用这个符号,名称还是被保留了下来)体现了更广义的将函数作为值的思想。你可以Xxx类里面定义一个x方法,然后写Xxx::x吗?确实是可以,但要是你没有方便的方法和类可用,而新的Lambda语法更简洁,它可以让你很简洁地表示一个行为或传递代码。现在你可以把Lambda表达式看作匿名功能,它基本上就是没有声明名称的方法,但和匿名类一样,它也可以作为参数传递给一个方法。
Lambda表达式最终结果就是你的代码变得更清晰、更灵活。比如,利用Lambda表达式,你可以更为简洁地自定义一个Comparator对象(本例子比较Apple的重量)
之前的实现方法
Comparator<Apple> byWeight = new Comparator<Apple>() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
};
使用Lambda表达式后
Comparator<Apple> byWeight = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
Lambda实例
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
传递代码的一个例子
假设你有一个Apple类,它有一个getColor方法,还有一个变量inventory保存着一个Apples的列表。你可能想要选出所有的绿苹果,并返回一个列表。通常我们用筛选(filter)一词来表达这个概念。在Java 8之前,你可能会写这样一个方法filterGreenApples:
public static List<Apple> filterGreenApples(List<Apple> inventory){
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory){
if ("green".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
但是接下来,有人可能想要选出重的苹果,比如超过150克,于是你心情沉重地写了下面这
个方法,甚至用了复制粘贴
public static List<Apple> filterHeavyApples(List<Apple> inventory){
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory){
if (apple.getWeight() > 150) {
result.add(apple);
}
}
return result;
}
我们前面提过了,Java 8会把条件代码作为参数传递进去,这样可以避免filter方法
出现重复的代码。现在你可以写
public static boolean isGreenApple(Apple apple) {
return "green".equals(apple.getColor());
}
public static boolean isHeavyApple(Apple apple) {
return apple.getWeight() > 150;
}
public interface Predicate<T>{
boolean test(T t);
}
static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p) {
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory){
if (p.test(apple)) {
result.add(apple);
}
}
return result;
}
要用它的话,你可以写:
//绿色
filterApples(inventory, Apple::isGreenApple);
//重量
filterApples(inventory, Apple::isHeavyApple);
把方法作为值来传递显然很有用,但要是为类似于isHeavyApple和isGreenApple这种可
能只用一两次的短方法写一堆定义有点儿烦人。不过Java 8也解决了这个问题,它引入了一套新
记法(匿名函数或Lambda),让你可以写
//绿色
filterApples(inventory, (Apple a) -> "green".equals(a.getColor()) );
//重量大于150
filterApples(inventory, (Apple a) -> a.getWeight() > 150 );
//重量小于80或者棕色
filterApples(inventory, (Apple a) -> a.getWeight() < 80 || "brown".equals(a.getColor()) );