jdk8预览

时间:2023-12-27 20:28:37

原文:http://www.techempower.com/blog/2013/03/26/everything-about-java-8/
1.接口增强

(1)接口可以定义static方法

java.util.Comparator:

public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {

    return (Comparator<T>)Comparators.NaturalOrderComparator.INSTANCE;

}

(2)接口可以有default方法

java.lang.Iterable:

public default void forEach(Consumer<? super T> action) {

    Objects.requireNonNull(action);

    for (T t : this) {

        action.accept(t);

    }

}

default方法不能够override:toString()、equals()、hashCode()方法。

An interface cannot provide a default implementation for any of the methods of the Object class。

接口不能够提供Object类里面的方法的default实现。

ps:接口看上去越来越像抽象类了。

2.Functional接口

一个接口只定义了一个abstract方法,这个接口就是“functional接口”,比如:java.lang.Runnable。

“functional接口”中可以定义default方法

新引入@FunctionalInterface来标记

3.Lambdas表达式

functional接口可以用Lambdas来实例化。

(int x, int y) -> { return x + y; } :两个入参,一个返回值

(x, y) -> x + y:两个入参,一个返回值,自动推断类型

x -> x * x:一个入参,一个返回值,自动推断类型

() -> x:没有入参,一个返回值

x -> { System.out.println(x); }:一个入参,没有返回值,自动推断类型

String::valueOf static方法引用

Object::toString  非static方法引用

x::toString   Capturing method reference

ArrayList::new  构造函数引用

以下是等价的:

方法引用        
等价的Lambdas表达式

String::valueOf
x -> String.valueOf(x)

Object::toString
x -> x.toString()

x::toString
() -> x.toString()

ArrayList::new
() -> new ArrayList<>()

ps:看到String::valueOf这种引用方式,不仅让人想起了C++。

如果Lambdas表达式和“functional接口”外形相似,二者就可以兼容:

Comparator<String> c = (a, b) -> Integer.compare(a.length(),b.length());

Comparator类的compare()方法接收两个String的入参,返回一个int,跟右边的Lambdas表达式兼容。

所谓的外形相似就是说:入参、返回、checked异常。

Runnable r = () -> { System.out.println("Running!"); }也是ok的。

Capturing 与 non-capturing lambdas

如果一个Lambdas表达式访问了{}范围以外的非static的变量或者对象,那就是个Capturing Lambdas表达式:

int x = 5;

return y -> x + y;

Lambdas表达式captures了变量x,x必须得是“final等效”的:要么是final的,要么没有被修改过。

是否是Capturing Lambdas与性能有关,non-capturing的性能更高,non-capturing只需要被evaluated一次,只有一个instance,

但是,每次遇到Capturing lambdas都会evaluated,类似于匿名内部类的实例化。

3.新添加包:java.util.function

这个包下面添加了很多functional接口:

Function<T, R> - take a T as input, return an R as ouput

Predicate<T> - take a T as input, return a boolean as output

Consumer<T> - take a T as input, perform some action and don't return anything

Supplier<T> - with nothing as input, return a T

BinaryOperator<T> - take two T's as input, return one T as output, useful for "reduce" operations

新添加了对应基本数据类型的功能函数类,比如:

IntConsumer接收int,无返回,主要是为了性能的原因,避免自动拆装箱。

4.新添加包:java.util.stream

java.util.stream这个包主要是为了support functional-style operations on streams of value。

常见的获取stream的方式是从Collection获取:

Stream<T> stream = collection.stream();

一个stream就类似于是一个Iterator,只能遍历一次,当然stream也可能是无穷的。

stream可能是串行的也可能是并行的。

stream能做什么呢?

int sumOfWeights = blocks.stream().filter(b -> b.getColor() == RED)

                                  .mapToInt(b -> b.getWeight())

                                  .sum();

以上使用了简单类型的stream,sum()方法只有在简单类型的stream上才有。

stream提供了api用来转换value,或者是对结果做一些操作,对stream的操作可以是“中间操作”也可能是“终止操作”。

中间操作:会保持stream处于打开的状态,并允许进一步的操作,上例中的filter()和mapToInt()就是中间操作,返回的还是当前的stream,允许更多的链式操作。

终止操作:必须是stream上的最后一个操作,一旦被调用,stream就被消费掉,而且不能再使用了。

一般来说,对stream的处理包含三个步骤:

(1)从源处获取stream

(2)做一个或多个中间操作

(3)做一个终止操作

Stream可以是有状态(Stateful)的。

stream是可以短路操作(Short-circuiting)的,比如在处理无穷的stream的时候就需要提前停止。

stream的api方法介绍:

中间操作:

filter:排除掉所有不满足预定条件的元素

map :使用Function对元素做一对一的转换

flatMap :把一个元素映射成0个或者多个元素

distinct :根据equals方法,排除掉所有的重复元素,这是个stateful的操作。

sorted :让元素有序,stateful

limit :让后续的操作只能看到最多limit个元素,stateful并且short-circuiting

substream :让后续的操作只能看到stream的一部分。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Dave");

List<String> filteredNames = names.stream().filter(e -> e.length() >= 4).collect(Collectors.toList());

for (String name : filteredNames) {

    System.out.println(name);  //Alice Charlie Dave

}

终止操作:

forEach :对stream的每一个元素做一些处理

toArray :把元素导出到数组里面

reduce :使用BinaryOperator,把多个stream组合成一个

collect :把元素导出到某个容器里面,比如:collection或者map

min,max ,count ,

anyMatch :是否至少一个匹配的元素,short-circuiting。

allMatch :是否所有的元素都匹配,short-circuiting。

noneMatch :是否所有的元素都不匹配,short-circuiting。

findFirst :找到第一个匹配的元素,hort-circuiting。

findAny :找到任何一个匹配的元素,hort-circuiting。

中间操作是延迟(lazy)的。只有终止操作才会触发对stream的处理。在终止操作开始的时候,无论有多少中间操作, 

the elements are then consumed in (usually, but not quite always) a single pass.所有的元素都是进行一次性处理,

有些Stateful操作(sorted(),distinct())可能会进行第二次处理。

有专门针对基本类型的stream:IntStream,LongStream,DoubleStream

List<String> strings = Arrays.asList("hello", "java", "");

Object[] list = strings.stream()                  // Stream<String>

        .mapToInt(String::length)                 // IntStream

        .mapToLong(x -> Long.valueOf(x))          // LongStream

        .mapToDouble(x -> x * 2.0)                // DoubleStream

        .boxed()                                  // Stream<Double>

        .toArray();

System.out.println(java.util.Arrays.toString(list));//[10.0, 8.0, 0.0]

5.泛型类型推断增强

java7里面:

foo(Utility.<Type>bar());

Utility.<Type>foo().bar();

但是java8里面:

foo(Utility.bar());

Utility.foo().bar();

6.新引入java.time包

LocalDateTime:日期+时间

LocalDate:日期

LocalTime:时间

Instant:类似于java.util.Date

DateTimeFormatter:与字符串的转化

与老的api转化:

Date.toInstant()

Date.from(Instant)

Calendar.toInstant()

7.新添加了Collections API

Iterable.forEach(Consumer)

Iterator.forEachRemaining(Consumer)

Collection.removeIf(Predicate)

Collection.spliterator()

Collection.stream()

Collection.parallelStream()

List.sort(Comparator)

List.replaceAll(UnaryOperator)

Map.forEach(BiConsumer)

Map.replaceAll(BiFunction)

Map.putIfAbsent(K, V)

Map.remove(Object, Object)

Map.replace(K, V, V)

Map.replace(K, V)

Map.computeIfAbsent(K, Function)

Map.computeIfPresent(K, BiFunction)

Map.compute(K, BiFunction)

Map.merge(K, V, BiFunction)

Map.getOrDefault(Object, V)

List<String> strings = Arrays.asList("a", "b", "c");

// Index strings by length:

Map<Integer, List<String>> map = new HashMap<>();

for (String s : strings) {

    map.computeIfAbsent(s.length(),key -> new ArrayList<String>()).add(s);

}

System.out.println(map);//{1=[a, b, c]}

把stram里面的元素放到colection或者map里面:

List<String> strings = Arrays.asList("a", "b", "c","hello","world");

// Although in this case the stream API may be a better choice:

Map<Integer, List<String>> map = strings.stream().collect(Collectors.groupingBy(String::length));

System.out.println(map);//{1=[a, b, c], 5=[hello, world]}

8.新添加了Concurrency API

ConcurrentHashMap被完全重写

9.新添加了Concurrency API

10.反射和注解增强

注解可以加在泛型参数上: List<@Nullable String>

11.Nashorn JavaScript Engine

12.其他的一些api:

Base64

StringJoiner

Objects.isNull(Object) 

Objects.nonNull(Object) 

ThreadLocal<List<String>> strings = ThreadLocal.withInital(ArrayList::new);

people.sort(

    Comparator.comparing(Person::getLastName)

        .thenComparing(Person::getFirstName)

        .thenComparing(

            Person::getEmailAddress,

            Comparator.nullsLast()

                .thenComparing(String.CASE_INSENSITIVE_ORDER)));

总之一句话,加入了lambda表达式的java越来越像动态语言了,源码也越来越看不懂了,估计得好好的适应一段时间了。