JDK8新特性详解

JDK8主要引入了这些新特性:

  1. 接口的默认实现
  2. Lambda表达式
  3. 函数式接口
  4. 方法与构造函数引用
  5. 内置了许多函数式接口
  6. Stream流

接口的默认实现

jdk8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字接口,这个特性又叫做拓展方法。

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

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

这个接口同时定义了两个方法calculatesqrt.只不过sqrt方法拥有自己的默认实现。

Lambda表达式

在老版本中我们对一个list进行排序,我们一般需要这样写:

1
2
3
4
5
6
7
8
9
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);
}
});

通过JDK8之后提供的Lambda表达式,可以避免使用匿名对象,可以这样写:

1
2
3
4
Collections.sort(names, (String a, String b) -> b.compareTo(a));
//编译器可以自动推导参数类型,所以我们甚至不需要写参数类型
Collections.sort(names, (a, b) -> b.compareTo(a));

Lambda的访问外层作用域与匿名对象类类似。可以直接访问标记了final的外层局部变量或者实例的字段以及静态变量。

函数式接口

所谓的函数式接口是指有且仅有一个抽象方法的接口。

函数式接口的写法如下:

1
2
3
4
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}

函数式接口的典型使用场景就是作为方法的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13

public class FunctionalInterface {

//函数式接口作为方法参数
private static void doSomething(MyFunctionalInterface inter) {
inter.myMethod(); // 调用自定义的函数式接口方法
}

public static void main(String[] args) {
// 调用使用函数式接口的方法
doSomething(() ‐> System.out.println("Lambda执行啦!"));
}
}

方法与构造函数引用

假如我们又这样一个函数式接口:

1
2
3
4
5
6
@FunctionalInterface
interface IConvert<F,T>{

//将F类型转换成T类型
T convert(F from);
}

我们可以这样使用这个新特性:

1
2
3
		IConvert<String, Integer> convertor = (from) -> ( Integer.parseInt(from));
//简化写法
IConvert<String, Integer> convertor = Integer::parseInt;

还可以引用对象的方法;

1
2
MyObject obj=new MyObject();
IConvert<String,String> convertor=something::startWith;

还可以引用构造函数

1
2
3
4
@FunctionalInterface
interface PersonFactory<P extends Person>{
P create(String firstName, String lastName);
}

我们可以通过引用构造函数实现工厂类:

1
2
PersonFactory<Person> factory = Person::new;
Person p = factory.create("zhuge", "xx");

内置函数式接口

JDK8中内置了许多函数式接口,包括Comparator和Runnable等,它们被添加了@FunctionalNterface注解,以用来支持Lambda表示式。

Stream流

Stream流提供了一种对集合Collection的方便的操作。

Filter过滤

1
2
3
4
5
6
7
List<String> list = Arrays.asList("hello","world","apple","people","sea",
"watch","table","book","school","help");
list
.stream() //获取stream
.filter(s -> s.startsWith("s")) //设置filter。中间操作
.forEach(System.out::println); //打印出流中的元素。终端操作

Sorted排序

1
2
3
4
5
list
.stream()
.sorted((a,b) -> b.compareTo(a))
.forEach(System.out::println);

Map

1
2
3
4
5
6
7
8
9
List<String> list = Arrays.asList("10","100","1000");

System.out.println("---- test map ----");
list
.stream()
.map(Integer::valueOf) //转换为整数
.map(a -> a + 1) //执行加一操作
.forEach(System.out::println);

Match匹配

这是一种终端操作,姐u共不是stream对象,而是boolean值。

1
2
3
4
5
boolean anyMatch(Predicate<? super T> predicate);
boolean allMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);


Count计数

这是一种终端操作,用来统计stream中元素的个数。

1
2
3
4
5
6
long count = 
list
.stream() //获取stream
.filter(s -> s.startsWith("s")) //设置filter。中间操作
.count();

Reduce

list[0]和list[1]执行操作,得到的结果为result。result再和list[2]执行操作,得到的结果result。依次进行,对所有元素执行一遍.根据上述描述也可以看出,这里的“操作”必须满足两个入参、返回值是同一类型的

比如求和:

1
2
3
4
5
6
7
8
9
10
List<Integer> list = Arrays.asList(1,2,3,4,5);

System.out.println("---- test reduce ----");
Optional<Integer> sum =
list
.stream()
.reduce((a,b) -> a + b);

sum.ifPresent(System.out::println);