跳转至

Java8介绍

1.接口默认方法

Java8 可以通过default关键字为接口提供一个非抽象的方法。

1
2
3
4
5
6
7
interface Formula {
    double calculate(int a);

    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}

子类只需要实现抽象方法calculate,sqrt方法可以被其他方法调用。

1
2
3
4
5
6
7
8
9
Formula formula = new Formula() {
    @Override
    public double calculate(int a) {
        return sqrt(a * 100);
    }
};

formula.calculate(100);     // 100.0
formula.sqrt(16);           // 4.0

2.Lambda表达式

在以前Java版本中,我们可以通过下面代码实现list的排序

1
2
3
4
5
6
7
8
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");

Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
    }
});

Java8提供了一种更简短的语法

1
2
3
Collections.sort(names, (String a, String b) -> {
    return b.compareTo(a);
});

如果方法体只有一行,你可以省略{}和return关键字。java编译器知道参数类型,所以也可以省略参数类型。

Collections.sort(names, (a, b) -> b.compareTo(a));

3.Functional接口

我们可以将任意只含一个抽象方法的接口用作lambda表达式。为了确保接口满足需求,应当添加一个@FunctionalInterface注解 ,当为接口添加两个抽象方法,编译器就会报错。

1
2
3
4
@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}
1
2
3
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);    // 123

4.方法和构造函数的引用

Java8允许使用::关键字传递方法或者构造函数的引用。所以上面的代码可以变成这样

1
2
3
Converter<String, Integer> converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted);   // 123

引用对象的方法

1
2
3
4
5
class Something {
    String startsWith(String s) {
        return String.valueOf(s.charAt(0));
    }
}
1
2
3
4
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);    // "J"

构造函数引用

class Person {
    String firstName;
    String lastName;

    Person() {}

    Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
1
2
3
interface PersonFactory<P extends Person> {
    P create(String firstName, String lastName);
}
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");

Java 编译器会自动选择正确的构造函数通过匹配PersonFactory.create的签名。

5.Lambda作用域

Lambda访问外部类的变量和匿名内部类非常相似。

读取外部类final修饰的局部变量。

1
2
3
4
5
final int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);

stringConverter.convert(2);     // 3

不同于内部类的是,变量num不一定必须声明为final。下面的代码也是可用的。

1
2
3
4
5
int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);

stringConverter.convert(2);     // 3

然后这里的num是暗含的final类型,下面的代码不能通过编译

1
2
3
4
int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);
num = 3;

在lambda表达式中也不允许改变num的值。

lambada不允许访问默认方法。下面的代码将不能通过编译。

Formula formula = (a) -> sqrt( a * 100);

6.内置Functional接口

7.Streams

Collections在Java 8中被扩展,可以调用Collection.stream()或者Collection.parallelStream()来创建stream。

首先来创建一个用于操作的集合

1
2
3
4
5
6
7
8
9
List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");

Filter

1
2
3
4
5
6
7
stringCollection
    .stream()
    .sorted()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);

// "aaa1", "aaa2"

Sorted

1
2
3
4
5
6
7
stringCollection
    .stream()
    .sorted()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);

// "aaa1", "aaa2"

参考

评论