java8学习笔记

参考:Java 8 Tutorial

  • how to use default interface methods, lambda expressions, method references and repeatable annotations.
  • most recent API changes like streams, functional interfaces, map extensions and the new Date API.

Interfaces

提供default来扩展接口的方法,不再仅仅可以使用abstract method的形式。

例子:

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

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

对应的使用:

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

Lambda表达式

查看一下代码的演变:

正常的写法:

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);
}
});

Lambda方式的写法:

1
2
3
4
5
6
7
8
# 演变一
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
# 演变二
Collections.sort(names, (String a, String b) -> b.compareTo(a));
# 演变二
Collections.sort(names, (a, b) -> b.compareTo(a));

@FunctionalInterface注解

exactly one abstract method declaration。
必须有且一个抽象方法。方便lambda表达式进行匹配。

如一下的例子:

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

Method and Constructor References

pass references of methods or constructors via the :: keyword
即:使用::来代替方法和构造函数的声明。

  • 静态方法的使用
1
Converter<String, Integer> converter = Integer::valueOf;
  • 普通的方法
1
2
3
4
5
6
7
8
9
class Something {
String startsWith(String s) {
return String.valueOf(s.charAt(0));
}
}
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted); // "J"
  • 代替构造函数
1
2
3
4
5
6
7
8
9
10
class Person {
String firstName;
String lastName;
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");

Accessing Default Interface Methods

Default methods cannot be accessed from within lambda expressions
即:interface声明的default方法并不能使用lambda表达式

下面并不能通过编译:

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

stream

感觉跟rxjava一样,找到影子啊。同样使用流式的方式和思想

介绍:

A java.util.Stream represents a sequence of elements on which one or more operations can be performed. Stream operations are either intermediate or terminal.

java.util.Collection进行扩展,提供了对应的获取stream的操作:

Collection.stream() or Collection.parallelStream()

下面用到的集合

1
2
List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");

下面是对应操作符的介绍:

Filter 过滤操作

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

// "aaa2", "aaa1"

当中的forEach将一个个数据输出,学过rxjava的人肯定很熟悉这个filter的操作符,感觉一模一样啊。

Sorted 排序

默认升序排序,当然可以自定义使用Comparator

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

Map 转换操作符

用理解rxjava来理解就好。

1
2
3
4
5
6
7
stringCollection
.stream()
.map(String::toUpperCase)
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);

// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"

Match 匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
boolean anyStartsWithA =
stringCollection
.stream()
.anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true
boolean allStartsWithA =
stringCollection
.stream()
.allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false

boolean noneStartsWithZ =
stringCollection
.stream()
.noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // true

Count 数量

1
2
3
4
5
6
long startsWithB =
stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();
System.out.println(startsWithB); // 3

Reduce 更改格式

1
2
3
4
5
6
7
Optional<String> reduced =
stringCollection
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"

Parallel Streams 平行流

Operations on sequential streams are performed on a single thread while operations on parallel streams are performed concurrent on multiple threads.
即:跟stream的区别是:stream为单线程,Parallel Streams为多线程.

使用Parallel Stream可以提高效率。

示例:排序sort耗时的比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int max = 1000000;
List<String> values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
# sort 耗时对比
long t0 = System.nanoTime();

long count = values.stream().sorted().count(); //Sequential sort
//long count = values.parallelStream().sorted().count(); //Parallel sort
System.out.println(count);

long t1 = System.nanoTime();

long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("sort took: %d ms", millis));

# 两者的耗时:
// sequential sort took: 899 ms
// parallel sort took: 472 ms

使用parallel sort快了将近50%.

Map集合扩展

As already mentioned maps don’t support streams. Instead maps now support various new and useful methods for doing common tasks.
由于map不支持stream,使用下面方法来做相同的事情

方法:

  • putIfAbsent 如果为null,将不被写入
  • forEach 对map集合每个元素的值进行操作。
1
2
3
4
for (int i = 0; i < 10; i++) {
map.putIfAbsent(i, "val" + i);
}
map.forEach((id, val) -> System.out.println(val));
  • remove (暂时这个不是很理解)
1
2
3
4
5
map.remove(3, "val3");
map.get(3); // val33

map.remove(3, "val33");
map.get(3); // null
  • getOrDefault 取不到的时候返回默认的值
1
map.getOrDefault(42, "not found");  // not found
  • Merge 合并:
    • 一种是存在key但没有对应的value时,
    • 另一种是存在key-value,通过第三个参数方法进行对value进行连接合并操作
1
2
3
4
5
map.merge(9, "val9", (value, newValue) -> value.concat(newValue));
map.get(9); // val9

map.merge(9, "concat", (value, newValue) -> value.concat(newValue));
map.get(9); // val9concat

Date API

介绍看原文吧。

Annotations

@Repeatable注解的介绍,没明白是来干什么的。

最后:

对应的代码实例:java8-tutorial

深入扩展:
Java 8 Stream Tutorial
Java 8 Nashorn Tutorial
Explore the JDK 8 API