Java8新特性

转自:http://www.oschina.NET/translate/everything-about-Java-8html

建议去看原文,此处转载只是为了记录。java

这篇文章是对Java 8中即将到来的改进作一个面向开发者的综合性的总结,JDK的这一特性将会在2013年9月份发布。linux

在写这篇文章的时候,java 8的开发工做仍然在紧张有序的进行中,语言特新和API仍然有可能改变,我会尽我最大的努力保持这份文档跟获得Java 8的改动。git

Java 8的预览版,也就是 “Project Lambda”,如今能够从java.net下载到。程序员

我使用了IntelliJ的预览版作个人IDE,在我看来他是目前支持java 8特性最好的一个IDE,你能够从这里下载到.算法

因为我没有找到Oracle发布的Java 8的官方文档,因此目前Java 8的文档还只有本地版本,等oracle公开文档的时候,我将会从新连接到官方文档。sql

JeromeCui
JeromeCui
翻译于 3年前

2人顶api

 翻译的不错哦!数组

接口改善

如今接口里已经彻底能够定义静态方法了. 举一个比较广泛的例子就是在java类库中, 对于一些接口如Foo, 都会有一个有静态方法的工具类Foos 来生成或者配合Foo对象实例来使用. 既然静态方法能够存在于接口当中, 那么大多数状况下 Foos工具类彻底可使用接口中的公共方法来代理 (或者将Foos置成package-private).数据结构

除此以外更重要的就是, Java 8中接口能够定义默认的方法了.举个例子,一个for-each循环的方法就能够加入到java.lang.Iterable中:

?
1
2
3
4
5
public default  void  forEach(Consumer<?  super T> action) {
     Objects.requireNonNull(action);  for (T t :  this ) {
         action.accept(t);
     }
}

在过去,java类库的接口中添加方法基本上是不可能的. 在接口中添加方法意味着破坏了实现了这个接口的代码. 可是如今, 只要可以提供一个正确明智的默认的方法的实现, java类库的维护者就能够在接口中添加方法.

Java 8中, 大量的默认方法已经被添加到核心的JDK接口中了. 稍候我会详细介绍它们.

叫我蝴蝶吧
叫我蝴蝶吧
翻译于 3年前

2人顶

 翻译的不错哦!

为何不能用默认方法来重载equals,hashCode和toString?

接口不能提供对Object类的任何方法的默认实现。特别是,这意味着从接口里不能提供对equals,hashCode或toString的默认实现。

这刚看起来挺奇怪的,但考虑到一些接口其实是在文档里定义他们的equals行为的。List接口就是一个例子了。所以,为何不容许这样呢?

Brian Goetz在这个问题上的冗长的回复里给出了4个缘由。我这里只说其中一个,由于那个已经足够说服我了:

它会变得更困难来推导何时该调用默认的方法。如今它变得很简单了:若是一个类实现了一个方法,那老是优先于默认的实现的。一旦全部接口的实例都是Object的子类,全部接口实例都已经有对equals/hashCode/toString的非默认实现。所以,一个在接口上这些的默认版本都是没用的,它也不会被编译。

要看更多的话,看下由Brian Goetz写的解释: 对“容许默认方法来重载Object的方法”的回复

excepiton
excepiton
翻译于 3年前

3人顶

 翻译的不错哦!

函数式接口

Java 8 引入的一个核心概念是函数式接口。若是一个接口定义个惟一一个抽象方法,那么这个接口就成为函数式接口。好比,java.lang.Runnable就是一个函数式接口,由于它只顶一个一个抽象方法:

?
1
public abstract  void  run();
留意到“abstract”修饰词在这里是隐含的,由于这个方法缺乏方法体。为了表示一个函数式接口,并不是想这段代码同样必定须要“abstract”关键字。

默认方法不是abstract的,因此一个函数式接口里能够定义任意多的默认方法,这取决于你。

同时,引入了一个新的Annotation:@FunctionalInterface。能够把他它放在一个接口前,表示这个接口是一个函数式接口。加上它的接口不会被编译,除非你设法把它变成一个函数式接口。它有点像@Override,都是声明了一种使用意图,避免你把它用错。

JoeyBlue
JoeyBlue
翻译于 3年前

6人顶

 翻译的不错哦!

Lambdas

一个函数式接口很是有价值的属性就是他们可以用lambdas来实例化。这里有一些lambdas的例子:

左边是指定类型的逗号分割的输入列表,右边是带有return的代码块:

?
1
( int x,  int y) -> {  return x + y; }

左边是推导类型的逗号分割的输入列表,右边是返回值:

?
1
(x, y) -> x + y

左边是推导类型的单一参数,右边是一个返回值:

?
1
x -> x * x

左边没有输入 (官方名称: "burger arrow"),在右边返回一个值:

?
1
() -> x

左边是推导类型的单一参数,右边是没返回值的代码块(返回void):

?
1
x -> { System.out.println(x); }

静态方法引用:

?
1
String::valueOf

非静态方法引用:

?
1
Object::toString

继承的函数引用:

?
1
x::toString

构造函数引用:

?
1
ArrayList:: new

你能够想出一些函数引用格式做为其余lambda格式的简写。

excepiton
excepiton
翻译于 3年前

3人顶

 翻译的不错哦!

方法引用  等价的lambda表达式
String::valueOf
x -> String.valueOf(x)
Object::toString
x -> x.toString()
x::toString
() -> x.toString()
ArrayList::new
() -> new ArrayList<>()

固然,在Java里方法能被重载。类能够有多个同名但不一样参数的方法。这一样对构造方法有效。ArrayList::new可以指向它的3个构造方法中任何一个。决定使用哪一个方法是根据在使用的函数式接口。

一个lambda和给定的函数式接口在“外型”匹配的时候兼容。经过“外型”,我指向输入、输出的类型和声明检查异常。

给出两个具体有效的例子:

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

一个Comparator<String>的compare方法须要输入两个阐述,而后返回一个int。这和lambda右侧的一致,所以这个任务是有效的。

?
1
Runnable r = () -> { System.out.println( "Running!" ); }

一个Runnable的run方法不须要参数也不会返回值。这和lambda右侧一致,因此任务有效。

在抽象方法的签名里的受检查异常(若是存在)也很重要。若是函数式接口在它的签名里声明了异常,lambda只能抛出受检查异常。

excepiton
excepiton
翻译于 3年前

3人顶

 翻译的不错哦!

捕获和非捕获的Lambda表达式

当Lambda表达式访问一个定义在Lambda表达式体外的非静态变量或者对象时,这个Lambda表达式称为“捕获的”。好比,下面这个lambda表达式捕捉了变量x:

?
1
int x =  5 return y -> x + y;
为了保证这个lambda表达式声明是正确的,被它捕获的变量必须是“有效final”的。因此要么它们须要用final修饰符号标记,要么保证它们在赋值后不能被改变。

Lambda表达式是不是捕获的和性能悄然相关。一个非不捕获的lambda一般比捕获的更高效,虽然这一点没有书面的规范说明(据我所知),并且也不能为了程序的正确性期望它作什么,非捕获的lambda只须要计算一次. 而后每次使用到它都会返回一个惟一的实例。而捕获的lambda表达式每次使用时都须要从新计算一次,并且从目前实现来看,它很像实例化一个匿名内部类的实例。


JoeyBlue
JoeyBlue
翻译于 3年前

3人顶

 翻译的不错哦!

lambdas不作的事

你应该记住,有一些lambdas不提供的特性。为了Java 8它们被考虑到了,可是没有被包括进去,因为简化以及时间限制的缘由。

Non-final* 变量捕获 - 若是一个变量被赋予新的数值,它将不能被用于lambda之中。"final"关键字不是必需的,但变量必须是“有效final”的(前面讨论过)。这个代码不会被编译:

?
1
2
3
4
int count =  0 ;
List<String> strings = Arrays.asList( "a" "b" "c" );
strings.forEach(s -> {
     count++;  // error: can't modify the value of count });

例外的透明度 - 若是一个已检测的例外可能从lambda内部抛出,功能性的接口也必须声明已检测例外能够被抛出。这种例外不会散布到其包含的方法。这个代码不会被编译:

?
1
2
3
void appendAll(Iterable<String> values, Appendable out)  throws IOException {  // doesn't help with the error values.forEach(s -> {
         out.append(s);  // error: can't throw IOException here // Consumer.accept(T) doesn't allow it });
}

有绕过这个的办法,你能定义本身的功能性接口,扩展Consumer的同时经过像RuntimeException之类抛出 IOException。我试图用代码写出来,但发现它使人困惑是否值得。

控制流程 (break, early return) -在上面的 forEach例子中,传统的继续方式有可能经过在lambda以内放置 "return;"来实现。可是,没有办法中断循环或者从lambda中经过包含方法的结果返回一个数值。例如:

?
1
2
3
4
5
final String secret =  "foo" boolean containsSecret(Iterable<String> values) {
     values.forEach(s -> {  if (secret.equals(s)) {
             ???  // want to end the loop and return true, but can't }
     });
}

进一步阅读关于这些问题的资料,看看这篇Brian Goetz写的说明:在 Block<T>中响应“已验证例外”

super0555
super0555
翻译于 3年前

3人顶

 翻译的不错哦!

其它翻译版本(1)

为何抽象类不能经过利用lambda实例化

抽象类,哪怕只声明了一个抽象方法,也不能使用lambda来实例化。

下面有两个类 Ordering 和 CacheLoader的例子,都带有一个抽象方法,摘自于Guava 库。那岂不是很高兴可以声明它们的实例,像这样使用lambda表达式?

Ordering<String> order = (a, b) -> ...;

?
1
CacheLoader<String, String> loader = (key) -> ...;

这样作引起的最多见的争论就是会增长阅读lambda的难度。以这种方式实例化一段抽象类将致使隐藏代码的执行:抽象类的构造方法。

另外一个缘由是,它抛出了lambda表达式可能的优化。在将来,它多是这种状况,lambda表达式都不会计算到对象实例。听任用户用lambda来声明抽象类将妨碍像这样的优化。

外,有一个简单地解决方法。事实上,上述两个摘自Guava 库的实例类已经证实了这种方法。增长工厂方法将lambda转换成实例。

?
1
2
Ordering<String> order = Ordering.from((a, b) -> ...);
CacheLoader<String, String> loader = CacheLoader.from((key) -> ...);

要深刻阅读,请参看由 Brian Goetz所作的说明: response to "Allow lambdas to implement abstract classes"

等PM
等PM
翻译于 3年前

1人顶

 翻译的不错哦!

java.util.function

包概要:java.util.function

做为Comparator 和Runnable早期的证实,在JDK中已经定义的接口恰巧做为函数接口而与lambdas表达式兼容。一样方式能够在你本身的代码中定义任何函数接口或第三方库。

但有特定形式的函数接口,且普遍的,通用的,在以前的JD卡中并不存在。大量的接口被添加到新的java.util.function 包中。下面是其中的一些:

  • Function<T, R> -T做为输入,返回的R做为输出
  • Predicate<T> -T做为输入,返回的boolean值做为输出
  • Consumer<T> - T做为输入,执行某种动做但没有返回值
  • Supplier<T> - 没有任何输入,返回T
  • BinaryOperator<T> -两个T做为输入,返回一个T做为输出,对于“reduce”操做颇有用

这些最原始的特征一样存在。他们以int,long和double的方式提供。例如:

  • IntConsumer -以int做为输入,执行某种动做,没有返回值

这里存在性能上的一些缘由,主要释在输入或输出的时候避免装箱和拆箱操做。

等PM
等PM
翻译于 3年前

1人顶

 翻译的不错哦!

java.util.stream

包汇总: java.util.stream

新的java.util.stream包提供了“支持在流上的函数式风格的值操做”(引用javadoc)的工具。可能活动一个流的最多见方法是从一个collection获取:

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

一个流就像一个地带器。这些值“流过”(模拟水流)而后他们离开。一个流能够只被遍历一次,而后被丢弃。流也能够无限使用。

流可以是 串行的 或者 并行的。 它们可使用其中一种方式开始,而后切换到另外的一种方式,使用stream.sequential()或stream.parallel()来达到这种切换。串行流在一个线程上连续操做。而并行流就可能一次出如今多个线程上。

因此,你想用一个流来干什么?这里是在javadoc包里给出的例子:

?
1
2
3
int sumOfWeights = blocks.stream().filter(b -> b.getColor() == RED)
                                   .mapToInt(b -> b.getWeight())
                                   .sum();

注意:上面的代码使用了一个原始的流,以及一个只能用在原始流上的sum()方法。下面立刻就会有更多关于原始流的细节。

excepiton
excepiton
翻译于 3年前

3人顶

 翻译的不错哦!

流提供了流畅的API,能够进行数据转换和对结果执行某些操做。流操做既能够是“中间的”也能够是“末端的”。

  • 中间的 -中间的操做保持流打开状态,并容许后续的操做。上面例子中的filter和map方法就是中间的操做。这些操做的返回数据类型是流;它们返回当前的流以便串联更多的操做。
  • 末端的 - 末端的操做必须是对流的最终操做。当一个末端操做被调用,流被“消耗”而且再也不可用。上面例子中的sum方法就是一个末端的操做。

一般,处理一个流涉及了这些步骤:

  1. 从某个源头得到一个流。
  2. 执行一个或更多的中间的操做。
  3. 执行一个末端的操做。

可能你想在一个方法中执行全部那些步骤。那样的话,你就要知道源头和流的属性,并且要能够保证它被正确的使用。你可能不想接受任意的Stream<T>实例做为你的方法的输入,由于它们可能具备你难以处理的特性,好比并行的或无限的。

super0555
super0555
翻译于 3年前

1人顶

 翻译的不错哦!

有几个更普通的关于流操做的特性须要考虑:

  • 有状态的 - 有状态的操做给流增长了一些新的属性,好比元素的惟一性,或者元素的最大数量,或者保证元素以排序的方式被处理。这些典型的要比无状态的中间操做代价大。
  • 短路 - 短路操做潜在的容许对流的操做尽早中止,而不去检查全部的元素。这是对无限流的一个特殊设计的属性;若是对流的操做没有短路,那么代码可能永远也不会终止。

对每一个Sttream方法这里有一些简短的,通常的描述。查阅javadoc获取更详尽的解释。下面给出了每一个操做的重载形式的连接。

中间的操做:

  • filter 1 - 排除全部与断言不匹配的元素。
  • map 1 2 3 4 - 经过Function对元素执行一对一的转换。
  • flatMap 1 2 3 4 5 - 经过FlatMapper将每一个元素转变为无或更多的元素。
  • peek 1 - 对每一个遇到的元素执行一些操做。主要对调试颇有用。
  • distinct 1 - 根据.equals行为排除全部重复的元素。这是一个有状态的操做。
  • sorted 1 2 - 确保流中的元素在后续的操做中,按照比较器(Comparator)决定的顺序访问。这是一个有状态的操做。
  • limit 1 - 保证后续的操做所能看到的最大数量的元素。这是一个有状态的短路的操做。
  • substream 1 2 - 确保后续的操做只能看到一个范围的(根据index)元素。像不能用于流的String.substring同样。也有两种形式,一种有一个开始索引,一种有一个结束索引。两者都是有状态的操做,有一个结束索引的形式也是一个短路的操做。

末端的操做:

  • forEach 1 - 对流中的每一个元素执行一些操做。
  • toArray 1 2 - 将流中的元素倾倒入一个数组。
  • reduce 1 2 3 - 经过一个二进制操做将流中的元素合并到一块儿。
  • collect 1 2 - 将流中的元素倾倒入某些容器,例如一个Collection或Map.
  • min 1 - 根据一个比较器找到流中元素的最小值。
  • max 1 -根据一个比较器找到流中元素的最大值。
  • count 1 - 计算流中元素的数量。
  • anyMatch 1 - 判断流中是否至少有一个元素匹配断言。这是一个短路的操做。
  • allMatch 1 - 判断流中是否每个元素都匹配断言。这是一个短路的操做。
  • noneMatch 1 - 判断流中是否没有一个元素匹配断言。这是一个短路的操做。
  • findFirst 1 - 查找流中的第一个元素。这是一个短路的操做。
  • findAny 1 - 查找流中的任意元素,可能对某些流要比findFirst代价低。这是一个短路的操做。

如 javadocs中提到的 , 中间的操做是延迟的(lazy)。只有末端的操做会当即开始流中元素的处理。在那个时刻,无论包含了多少中间的操做,元素会在一个传递中处理(一般,但并不老是)。(有状态的操做如sorted() 和distinct()可能须要对元素的二次传送。) 

super0555
super0555
翻译于 3年前

1人顶

 翻译的不错哦!

流试图尽量作不多的工做。有一些细微优化,如当能够断定元素已经有序的时候,省略一个sorted()操做。在包含limit(x) 或 substream(x,y)的操做中,有些时候对一些不会决定结果的元素,流能够避免执行中间的map操做。在这里我不许备实现公平判断;它经过许多细微的但却很重要的方法表现得很聪明,并且它仍在进步。

回到并行流的概念,重要的是要意识到并行不是毫无代价的。从性能的立场它不是无代价的,你不能简单的将顺序流替换为并行流,且不作进一步思考就指望获得相同的结果。在你能(或者应该)并行化一个流之前,须要考虑不少特性,关于流、它的操做以及数据的目标方面。例如:访问顺序确实对我有影响吗?个人函数是无状态的吗?个人流有足够大,而且个人操做有足够复杂,这些能使得并行化是值得的吗?

super0555
super0555
翻译于 3年前

1人顶

 翻译的不错哦!

有针对int,long和double的专业原始的Stream版本:

能够在众多函数中,经过专业原始的map和flatMap函数,在一个stream对象与一个原始stream对象之间来回转换。给几个虚设例子:

?
1
2
3
4
5
6
List<String> strings = Arrays.asList( "a" "b" "c" );
strings.stream()  //
Stream<String> .mapToInt(String::length)  // IntStream .longs() //
LongStream .mapToDouble(x -> x /  10.0 // DoubleStream .boxed() //
Stream<Double> .mapToLong(x -> 1L)  // LongStream .mapToObj(x -> "") //
Stream<String> ...

原始的stream也为得到关于stream的基础数据统计提供方法,那些stream是指做为数据结构的。你能够发现count, sum, min, max, 以及元素平均值所有是来自于一个终端的操做。

原始类型的剩余部分没有原始版本,由于这须要一个不可接受的JDK数量的膨胀。IntStream, LongStream, 和 DoubleStream被认为很是有用应当被包含进去,其余的数字型原始stream能够由这三个经过扩展的原始转换来表示。

super0555
super0555
翻译于 3年前

2人顶

 翻译的不错哦!

在flatMap操做中使用的  FlatMapper 接口是具备一个抽象方法的功能性接口:
?
1
void flattenInto(T element, Consumer<U> sink);

在一个flatMap操做的上下文中,stream为你提供element和 sink,而后你定义该用element 和 sink作什么。element是指在stream中的当前元素,而sink表明当flatMap操做结束以后在stream中应该显示些什么。例如:

?
1
2
3
4
5
6
7
8
Set<Color> colors = ...;
List<Person> people = ...;
Stream<Color> stream = people.stream().flatMap(
     (Person person, Consumer<Color> sink) -> {  // Map each person to the colors they like. for (Color color : colors) { if (person.likesColor(color)) {
                 sink.accept(color);
             }
         }
     });

注意上面lambda中的参数类型是指定的。在大多数其它上下文中,你能够不须要指定类型,但这里因为FlatMapper的天然特性,编译器须要你帮助断定类型。若是你在使用flatMap又迷惑于它为何不编译,多是由于你没有指定类型。

最使人感到困惑,复杂并且有用的终端stream操做之一是collect。它引入了一个称为Collector的新的非功能性接口。这个接口有些难理解,但幸运的是有一个Collectors工具类可用来产生全部类型的有用的Collectors。例如:

?
1
2
3
4
List<String> strings = values.stream()
                              .filter(...)
                              .map(...)
                              .collect(Collectors.toList());

若是你想将你的stream元素放进一个Collection,Map或String,那么Collectors可能具备你须要的。在javadoc中浏览那个类绝对是值得的。

super0555
super0555
翻译于 3年前

2人顶

 翻译的不错哦!

泛型接口改进

建议摘要:JEP 101: 通用化目标-Type 接口

这是一个之前不能作到的,对编译器断定泛型能力的努力改进。在之前版本的Java中有许多情形编译器不能给某个方法计算出泛型,当方法处于嵌套的或串联方法调用这样的上下文的时候,即便有时候对程序员来讲它看起来“很明显”。那些状况须要程序员明确的指定一个“类型见证”(type witness)。它是一种通用的特性,但吃惊的是不多有Java程序员知道(我这么说是基于私下的交流而且阅读了一些StackOverflow的问题)。它看起来像这样:

?
1
2
// In Java 7: foo(Utility.<Type>bar());
Utility.<Type>foo().bar();

若是没有类型见证,编译器可能会将<Object>替代为泛型,并且若是须要的是一个更具体的类型,代码将编译失败。

Java 8 极大的改进了这个情况。在更多的案例中,它能够基于上下文计算出更多的特定的泛型类型。
?
1
2
// In Java 8: foo(Utility.bar());
Utility.foo().bar();

这项工做仍在发展中,因此我不肯定建议中列出的例子有多少能真正包含进Java 8。但愿是它们所有。

super0555
super0555
翻译于 3年前

1人顶

 翻译的不错哦!

其它翻译版本(1)

java.time

包概要: java.time

在Java8中新的 date/timeAPI存在于 java.time包中。若是你熟悉Joda Time,它将很容易掌握。事实上,我认为如此好的设计,以致于从未据说过 Joda Time的人也能很容易的掌握。

几乎在API中的任何东西都是永恒的,包括值类型和格式化 。对于Date域或者处理或处理本地线程日期格式化没必要太过担忧。

与传统的date/timeAPI的交叉是最小的。有一个清晰的分段:


新API对于像月份和每周的天数,喜欢枚举类型更赛过整形常量。

那么,那是什么呢?包级别的javadocs 对额外类型的作出了很是好的阐述。我将对一些值得注意的部分作一些简短的纲要。

很是有用的值类型:

其余有用的类型:

  • DateTimeFormatter - 将日期类型转换成字符串类型
  • ChronoUnit - 计算出两点之间的时间量,例如ChronoUnit.DAYS.between(t1, t2)
  • TemporalAdjuster - 例如date.with(TemporalAdjuster.firstDayOfMonth())

大多数状况下,新的值类型由JDBC提供支持。有一小部分异常,如ZonedDateTime在SQL中没有对应的(类型)。

等PM
等PM
翻译于 3年前

2人顶

 翻译的不错哦!

集合API附件

实际上接口可以定义默认方法容许了JDK做者加入大量的附件到集合API接口中。默认实如今核心接口里提供,而其余更有效或更好的重载实现被加入到可适用的具体类中。

这里是新方法的列表:

一样, Iterator.remove() 如今有一个默认的, 会抛出异常的实现,使得它稍微容易地去定义不可修改的迭代器。

Collection.stream()和Collection.parallelStream()是流API的主要门户。有其余方法去生成流,但这些在之后会更为长用。

List.sort(Comparator)的附件有点怪异。之前排序一个ArrayList的方法是:

?
1
Collections.sort(list, comparator);

这代码是你在Java7里惟一可选的,很是低效。它会复制list到一个数组里,排序这个数组,而后使用ListIterator来把数组插入到新list的新位置上。

excepiton
excepiton
翻译于 3年前

2人顶

 翻译的不错哦!

List.sort(比较器)的默认实现仍然会作这个,可是具体的实现类能够自由的优化。例如,ArrayList.sort在ArrayList内部数组上调用了Arrays.sort。CopyOnWriteArrayList作了一样的事情。

从这些新方法中得到的不只仅是性能。它们也具备更多的使人满意的语义。例如, 对Collections.synchronizedList()排序是一个使用了list.sort的原子操做。你可使用list.forEach对它的全部元素进行迭代,使之成为原子操做。

Map.computeIfAbsent使得操做相似多重映射的结构变得容易了:

?
1
2
3
4
5
6
7
8
// 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);
// Although in this case the stream API may be a better choice:
  Map<Integer, List<String>> map = strings.stream()
     .collect(Collectors.groupingBy(String::length));
super0555
super0555
翻译于 3年前

2人顶

 翻译的不错哦!

增长并发API

有太多的连接能够点击,所以参看ConcurrentHashMap javadocs文档以得到更多信息。

  • ConcurrentHashMap.reduce...
  • ConcurrentHashMap.search...
  • ConcurrentHashMap.forEach...
ForkJoinPool.commonPool()是处理全部并行流操做的结构。当你  须要的时候,它是一个好而简单的方式去得到一个ForkJoinPool/ExecutorService/Executor对象。ConcurrentHashMap<K, V>彻底重写。内部看起来它一点不像是Java7版本。从外部来看几乎相同,除了它有大量批量操做方法:多种形式的减小搜索和forEach。
ConcurrentHashMap.newKeySet()提供了一个并发的java.util.Set实现。它基本上是Collections.newSetFromMap(new ConcurrentHashMap<T, Boolean>())的另外一种方式的重写。
等PM
等PM
翻译于 3年前

2人顶

 翻译的不错哦!

StampedLock是一种新型锁的实现,极可能在大多数场景均可以替代ReentrantReadWriteLock。看成为一个简单的读写锁的时候,它比RRWL的性能要好。它也为“读优化”提供了API,经过它你得到了一个功能有点弱,但代价很小的读操做锁的版本,执行读操做,而后检查锁是否被一个写操做设定为无效。在Heinz Kabutz汇总的一系列幻灯片中,有更多关于这个类及其性能的细节(在这个系列幻灯片大约一半的地方开始的):"移相器和StampedLock演示"

CompletableFuture<T>是Future接口的一个很是棒的实现,它提供了无数执行(和串接)异步任务的方法。它特别依赖功能性的接口;lambdas是值得增长这个类的一个重要缘由。若是你正在使用Guava的 Future工具,例如Futures,ListenableFuture, 和 SettableFuture,那么你可能会但愿校验CompletableFuture可否做为潜在的替代选择。

super0555
super0555
翻译于 3年前

1人顶

 翻译的不错哦!

IO/NIO API的新增内容

简单的说,这些API用于从文件和InputStreams获取java.util.stream.Stream对象。不过它们与直接从常规的collection获得的流有些不一样,它们引入了两个概念:

  • UncheckedIOException - 当有IO错误时抛出这个异常,不过因为Iterator/Stream的签名中不容许有IOException,因此它只能借助于unchecked异常。
  • CloseableStream - 能够(而且应该)定义在 try-with-resources 语句里面的流。
zicode
zicode
翻译于 3年前

1人顶

 翻译的不错哦!

反射和annotation的改动

Annotation容许在更多的地方被使用,例如List<@Nullable String>。受此影响最大的多是那些静态分析工具,如Sonar和FindBugs。

JSR 308的网站解释了增长这些改动的动机,介绍的不错: "类型Annotation (JSR 308) 和 Checker框架"

zicode
zicode
翻译于 3年前

1人顶

 翻译的不错哦!

其它翻译版本(1)

Nashorn JavaScript 引擎

提案的摘要: JEP 174: Nashorn JavaScript 引擎

我对Nashorn没什么经验,于是我对上面提案所描述的所知甚少。简单的说,它是 Rhino 的接替者。Rhino 显得有些老了,而且有点慢,开发者决定最好仍是从头作一个。

zicode
zicode
翻译于 3年前

0人顶

 翻译的不错哦!

其余新增,涉及java.lang,java.util,和java.sql

这里能够介绍的太多了,只能挑一些最须要注意的项目。

ThreadLocal.withInitial(Supplier<T>) 能够在定义thread-local变量时更好的进行初始化。以前你初始化变量时是这样的:

?
1
2
3
ThreadLocal<List<String>> strings =  new ThreadLocal<List<String>>() {  @Override protected  List<String> initialValue() {  return new  ArrayList<>();
         }
     };
如今则是这样: 
?
1
2
ThreadLocal<List<String>> strings =
     ThreadLocal.withInital(ArrayList:: new );

stream的API的返回值有一个可选的<T>,就像min/max, findFirst/Any, 以及reduce的某些形式。这样作是由于stream中可能没有任何元素,可是它要提供一个一致的API,既能够处理“一些结果”,也能够处理“没有结果”。你能够提供默认值,抛异常,或者只在有结果的时候执行一些动做。

zicode
zicode
翻译于 3年前

1人顶

 翻译的不错哦!

它与Guava's Optional类很是很是的类似。它一点都不像是在Scala里的操做,也不会试图成为之一,有类似的地方纯属巧合。 

旁白:Java 8's Optional和Guava's Optional最终如此的类似是颇有趣的事,尽管荒谬的辩论发生在这两个库。

"FYI.... Optional was the cause of possibly the single greatest conflagration on the internal Java libraries discussion lists ever."

Kevin Bourrillion在 response to "Some new Guava classes targeted for release 10"如实写到:

"On a purely practical note, the discussions surrounding Optional have exceeded its design budget by several orders of magnitude."
Brian Goetz 在   response to "Optional require(s) NonNull"写到。

StringJoinerandString.join(...)来得太晚了。他们来得如此之晚以致于大多数Java开发者已经为字符串联合编写或发现了有用的工具,但这对JDK自己来讲很每秒,由于最终本身实现这一点。每一个人都会遇到要求字符串链接的情形,咱们如今可以经过每一个Java开发者(事实上的)即将知道的标准的API来阐明,这也算是一件好事。
ComparatorsandComparator.thenComparing(...)提供了很是优秀的工具,基于链的比较和基于域的比较。像这样:

?
1
2
people.sort(Comparators.comparing(Person::getLastName)
                        .thenComparing(Person::getFirstName));

这些新增功能提供了良好的,复杂的各类可读的简写。大多数用例由JDK里增长的 ComparisonChain和Ordering工具类来提供服务。对于什么是有价值的,我认为JDK版本比在Guava-ese里功能等效的版本的可读性好了不少。

相关文章
相关标签/搜索