TechEmpower 是位于加利福尼亚州埃尔塞贡多的一家定制应用开发公司,该公司发表了一篇题为“ Java 8 全面解析”的博客文章。该博客文章全面概括了开发者在即将到来的 Java 8 中所要面对的变化。下面的内容快速概括了该博客文章中的信息。如果想查看所有的细节请访问 TechEmpower 的博客文章。
改进接口
现在可以在接口中定义静态方法了。例如,java.util.Comparator 接口中现在拥有一个静态的 naturalOrder 方法。
public static <T extends Comparable<? super T>> Comparator <T>naturalOrder() { return (Comparator<T>) Cmparators.NaturalOrderComparator.INSTANCE; }
还能够在接口中提供默认方法。通过该功能,程序员能够在不破坏已有的接口实现代码的前提下添加新方法。例如,java.lang.Iterable 接口现在拥有一个默认的 forEach 方法。
public default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }
注意,接口不能为 Object 类中的任何方法提供默认的实现。
函数式接口
函数式接口是只定义了一个抽象方法的接口。Java 8 引入了 FunctionalInterface 注解来表明一个接口打算成为一个函数式接口。例如,java.lang.Runnable 就是一个函数式接口。
@FunctionalInterface public interface Runnable { public abstract void run(); }
注意,不管 FunctionalInterface 注解是否存在,Java 编译器都会将所有满足该定义的接口看作是函数式接口。
Lambda
函数式接口的重要属性是:我们能够使用 lambda 实例化它们,Lambda 表达式让你能够将函数作为方法参数,或者将代码作为数据对待。下面是 Lambda 的一些例子。输入在左边,代码在右边。输入类型能够被推断出来,同时是可选的。
(int x, int y) ->{ return x + y; } (x, y) -> x + y x -> x * x () -> x x -> { System.out.println(x); }
下面是实例化 Runnable 函数式接口的一个例子。
Runnable r = () ->{ System.out.println("Running!"); }
方法引用
方法引用是简洁的 Lambda 表达式,能够用于已经拥有名称的方法。下面是一些方法引用的例子,右边是同样效果的 Lambda 表达式。
String::valueOf x ->String.valueOf(x) Object::toString x ->x.toString() x::toString () ->x.toString() ArrayList::new () -> new ArrayList<>()
与捕获相对的非捕获 Lambda
如果使用 Lambda 表达式访问一个在 Lambda 语句体外定义的非静态变量或者对象,那么它会被说成是“捕获”。例如,下面的 Lambda 会访问变量 x:
int x = 5; return y -> x + y;
一个 Lambda 表达式仅能够访问 final 或者有效 final 封闭块中的局部变量和参数。
java.util.function
新版本向 java.util.function 包中添加了很多新的函数式接口。下面是一些例子:
- Function<T, R>——将 T 作为输入,返回 R 作为输出
- Predicate
——将 T 作为输入,返回一个布尔值作为输出 - Consumer
——将 T 作为输入,不返回任何内容 - Supplier
——没有输入,返回 T - BinaryOperator
——将两个 T 作为输入,返回一个 T 作为输出
java.util.stream
新的 java.util.stream 包提供了对值流进行函数式操作的类。从一个集合中获取流的一种常见方式是:
Stream<T> stream = collection.stream();
下面是一个来自于 Javadocs 包中的例子。
intsumOfWeights = blocks.stream().filter(b ->b.getColor() == RED) .mapToInt(b ->b.getWeight()) .sum();
在该例子中我们首先使用了一个块集合作为流的来源,然后在流上执行了 filter-map-reduce 操作获取红块重量的和。
流可以是无限的、有状态的,可以是顺序的,也可以是并行的。在使用流的时候,你首先需要从一些来源中获取一个流,执行一个或者多个中间操作,然后执行一个最终操作。中间操作包括 filter、map、flatMap、peel、distinct、sorted、limit 和 substream。终止操作包括 forEach、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst 和 findAny。 java.util.stream.Collectors 是一个非常有用的实用类。该类实现了很多归约操作,例如将流转换成集合和聚合元素。
改进了泛型推断
这提升了 Java 编译器推断泛型和在泛型方法调用中减少显式类型参数的能力。在 Java 7 中,代码如下:
foo(Utility.<Type>bar()); Utility.<Type>foo().bar();
在 Java 8 中,改进后的参数和调用链推断让你能够按照下面的方式编写代码:
foo(Utility.bar()); Utility.foo().bar();
java.time
新的日期 / 时间 API 包含在 java.time 包中。所有的类都是不可变且线程安全的。日期和时间类型包括 Instant、LocalDate、LocalTime、LocalDateTime 和 ZonedDateTime。除了日期和时间之外,还有 Duration 和 Period 类型。另外,值类型包括 Month、DayOfWeek、Year、 Month、YearMonth、MonthDay、OffsetTime 和 OffsetDateTime。这些新的日期 / 时间类大部分 JDBC 都支持。
新增集合 API
接口可以拥有默认函数的能力让 Java 8 得以向集合 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)
新增并发 API
Java 8 还向并发 API 中添加了一些新内容,我们将会在此简要介绍其中的一部分。ForkJoinPool.commonPool() 是处理所有并行流操作的结构。没有明确提交到某个特定池中的所有 ForkJoinTask 都将会使用通用池。ConcurrentHashMap 已经被完全重写。StampedLock 是一个新的锁实现,它可以作为 ReentrantReadWriteLock 的一个备选方案。CompletableFuture 是 Future 接口的一个实现,它为异步任务的执行和链接提供了方法。
新增 IO/NIO API
在 Java 8 中有一些新的 IO/NIO 方法,我们能够使用它们从文件或者输入流中获取 java.util.stream.Stream。
- BufferedReader.lines()
- Files.list(Path)
- Files.walk(Path, int, FileVisitOption…)
- Files.walk(Path, FileVisitOption…)
- Files.find(Path, int, BiPredicate, FileVisitOption…)
- Files.lines(Path, Charset)
- DirectoryStream.stream()
这里面有一个新的 UncheckedIOException,它是一个继承了 RuntimetimeException 的 IOException。还有一个 CloseableStream,它是一个能够并且应该被关闭的流。
反射和注解的变化
通过类型注解,我们能够在更多的地方使用注解,例如像List<@Nullable String> 这样的泛型参数中。这增强了通过静态分析工具发现错误的能力,它将增强并重定义Java 内置的类型系统。
Nashorn JavaScript 引擎
Nashorn 是一个集成到 JDK 中的新的、轻量级、高性能的 JavaScript 实现。Nashorn 是 Rhino 的继任者,它提升了性能和内存使用情况。它将会支持 javax.script API,但是它并不会支持 DOM/CSS,也不会包含浏览器插件 API。
java.lang、java.util 等其他地方的新增功能
Java 8 还向很多其他的包中添加了大量其他的功能,在本文中我们并没有提及。下面是一些值得注意的内容。可以使用 ThreadLocal.withInitial(Supplier) 更加简洁的声明本地线程变量。长期未兑现的 StringJoiner 和 String.join(…) 现在已经是 Java 8 的一部分了。比较器提供了一些新的方法能够用于链接和基于域的比较。默认的字符串池映射大小更大了,大约在 25—50K。
如果想要获取更加详细的介绍可以访问博客文章 Java 8 全面解析。该博客文章的最后一次更新时间是 2013 年 5 月 29 日。
查看英文原文: Everything About Java 8
评论