一:接口上定义的方法可以存在方法体
二:支持Lambda 表达式
首先看看在老版本的Java中是如何排列字符串的:只需要给静态方法 Collections.sort 传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。
在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:
对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字,但是你还可以写得更短点:
Lambda的一些解释:
函数式接口
Java 8 引入的一个核心概念是函数式接口。如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口。比如,java.lang.Runnable就是一个函数式接口,因为它只顶一个一个抽象方法:
1
public abstract void run();
留意到“abstract”修饰词在这里是隐含的,因为这个方法缺少方法体。为了表示一个函数式接口,并非想这段代码一样一定需要“abstract”关键字。
默认方法不是abstract的,所以一个函数式接口里可以定义任意多的默认方法,这取决于你。
同时,引入了一个新的Annotation:@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口。加上它的接口不会被编译,除非你设法把它变成一个函数式接口。它有点像@Override,都是声明了一种使用意图,避免你把它用错。
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格式的简写。
方法引用
等价的lambda表达式
String::valueOf
x -> String.valueOf(x)
Object::toString
x -> x.toString()
x::toString
() -> x.toString()
ArrayList::new
() -> new ArrayList<>()
当然,在Java里方法能被重载。类可以有多个同名但不同参数的方法。这同样对构造方法有效。ArrayList::new能够指向它的3个构造方法中任何一个。决定使用哪个方法是根据在使用的函数式接口。
其他:
增加并发API
· ForkJoinPool.commonPool()
· ConcurrentHashMap(v8)
· 下面的形式有并行,顺序,对象,整型,长整型和double型。
有太多的链接可以点击,因此参看ConcurrentHashMap javadocs文档以获得更多信息。
· ConcurrentHashMap.reduce...
· ConcurrentHashMap.search...
· ConcurrentHashMap.forEach...
· ConcurrentHashMap.newKeySet()
· ConcurrentHashMap.newKeySet(int)
· CompletableFuture
· StampedLock
· LongAdder
· LongAccumulator
· DoubleAdder
· DoubleAccumulator
· CountedCompleter
· Executors.newWorkStealingPool()
· Executors.newWorkStealingPool(int)
· 下面的形式有AtomicReference, AtomicInteger, AtomicLong, 和每一个原子数组的版本。
· AtomicReference.getAndUpdate(UnaryOperator)
· AtomicReference.updateAndGet(UnaryOperator)
· AtomicReference.getAndAccumulate(V, UnaryOperator)
· AtomicReference.accumulateAndGet(V, UnaryOperator)
ForkJoinPool.commonPool()是处理所有并行流操作的结构。当你 需要的时候,它是一个好而简单的方式去获得一个ForkJoinPool/ExecutorService/Executor对象。ConcurrentHashMap<K, V>完全重写。内部看起来它一点不像是Java7版本。从外部来看几乎相同,除了它有大量批量操作方法:多种形式的减少搜索和forEach。
ConcurrentHashMap.newKeySet()提供了一个并发的java.util.Set实现。它基本上是Collections.newSetFromMap(new ConcurrentHashMap<T, Boolean>())的另一种方式的重写。StampedLock是一种新型锁的实现,很可能在大多数场景都可以替代ReentrantReadWriteLock。当作为一个简单的读写锁的时候,它比RRWL的性能要好。它也为“读优化”提供了API,通过它你获得了一个功能有点弱,但代价很小的读操作锁的版本,执行读操作,然后检查锁是否被一个写操作设定为无效。在Heinz Kabutz汇总的一系列幻灯片中,有更多关于这个类及其性能的细节(在这个系列幻灯片大约一半的地方开始的):"移相器和StampedLock演示"
CompletableFuture<T>是Future接口的一个非常棒的实现,它提供了无数执行(和串接)异步任务的方法。它特别依赖功能性的接口;lambdas是值得增加这个类的一个重要原因。如果你正在使用Guava的 Future工具,例如Futures,ListenableFuture, 和 SettableFuture,那么你可能会希望校验CompletableFuture能否作为潜在的替代选择。
IO/NIO API的新增内容
· 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.entries()
简单的说,这些API用于从文件和InputStreams获取java.util.stream.Stream对象。不过它们与直接从常规的collection得到的流有些不同,它们引入了两个概念:
· UncheckedIOException - 当有IO错误时抛出这个异常,不过由于Iterator/Stream的签名中不允许有IOException,所以它只能借助于unchecked异常。
· CloseableStream - 可以(并且应该)定义在 try-with-resources 语句里面的流。
反射和annotation的改动
· 类型annotation (JSR 308)
· AnnotatedType
· Repeatable
· Method.getAnnotatedReturnType()
· Field.getAnnotationsByType(Class)
· Field.getAnnotatedType()
· Constructor.getAnnotatedReturnType()
· Parameter - 支持 parameter.getName(),等等。
Annotation允许在更多的地方被使用,例如List<@Nullable String>。受此影响最大的可能是那些静态分析工具,如Sonar和FindBugs。
JSR 308的网站解释了增加这些改动的动机,介绍的不错: "类型Annotation (JSR 308) 和 Checker框架"
Nashorn JavaScript 引擎
提案的摘要: JEP 174: Nashorn JavaScript 引擎
我对Nashorn没什么经验,因而我对上面提案所描述的所知甚少。简单的说,它是 Rhino 的接替者。Rhino 显得有些老了,并且有点慢,开发者决定最好还是从头做一个。
其他新增,涉及java.lang,java.util,和java.sql
· ThreadLocal.withInitial(Supplier)
· String.join(CharSequence, Charsequence...)
· String.join(CharSequence, Iterable)
· 下面的方法适用于所有数字的原语类型,并且作为这些类型的包装(wrapper)类的三个方法。hashCode方法除外,它们的作用是作为BinaryOperatorin的reduce操作的参数。关于这些方法还有很多的链接,更多的内容,参考Integer, Long, Double, Float, Byte, Short, 和 Character 的javadoc。
· Primitive.min(primitive, primitive);
· Primitive.max(primitive, primitive);
· Primitive.sum(primitive, primitive);
· Primitive.hashCode(primitive)
· 同样,下面新增的 Boolean 的方法可用于BinaryOperator<Boolean>:
· Boolean.logicalAnd(boolean, boolean)
· Boolean.logicalOr(boolean, boolean)
· Boolean.logicalXor(boolean, boolean)
· Optional
· OptionalInt
· OptionalLong
· OptionalDouble
· Base64
· StringJoiner
· Spliterator
· Spliterators
· Comparator.reverseOrder()
· Comparator.thenComparing(Comparator)
· Comparator.thenComparing(Function, Comparator)
· Comparator.thenComparing(Function)
· Comparator.thenComparing(ToIntFunction)
· Comparator.thenComparing(ToLongFunction)
· Comparator.thenComparing(ToDoubleFunction)
· Comparators
· 下面的方法适用于数组,支持T[], int[], long[], double[]。关于这些方法有很多链接,更多信息参考 Arrays 的javadoc。
· Arrays.spliterator(array)
· Arrays.spliterator(array, int, int)
· Arrays.stream(array)
· Arrays.stream(array, int, int);
· Arrays.parallelStream(array)
· Arrays.parallelStream(array, int, int);
· Arrays.setAll(array, IntFunction)
· Arrays.parallelSetAll(array, IntFunction)
· Math.toIntExact(long)
· Math.addExact(int, int)
· Math.subtractExact(int, int)
· Math.multiplyExact(int, int)
· Math.floorDiv(int, int)
· Math.floorMod(int, int)
· Math.addExact(long, long)
· Math.subtractExact(long, long)
· Math.multiplyExact(long, long)
· Math.floorDiv(long, long)
· Math.floorMod(long, long)
· Integer.toUnsignedLong(int)
· Integer.toUnsignedString(int)
· Integer.toUnsignedString(int, int)
· Integer.parseUnsignedInt(String)
· Integer.parseUnsignedInt(String, int)
· Integer.compareUnsigned(int, int)
· Long.toUnsignedString(long, int)
· Long.toUnsignedString(long)
· Long.parseUnsignedLong(String, int)
· Long.parseUnsignedLong(String)
· Long.compareUnsigned(long, long)
· Long.divideUnsigned(long, long)
· Long.remainderUnsigned(long, long)
· BigInteger.longValueExact()
· BigInteger.intValueExact()
· BigInteger.shortValueExact()
· BigInteger.byteValueExact()
· Objects.isNull(Object) - 可用作谓词,例如stream.anyMatch(Objects::isNull)
· Objects.nonNull(Object) - 可用作谓词,stream.filter(Objects::nonNull)
· Random.ints()
· Random.longs()
· Random.doubles()
· Random.gaussians()
· BitSet.stream()
· IntSummaryStatistics
· LongSummaryStatistics
· DoubleSummaryStatistics
· Logger的杂项新增
· Locale的杂项新增
· ResultSet的杂项新增
这里可以介绍的太多了,只能挑一些最需要注意的项目。
ThreadLocal.withInitial(Supplier<T>) 可以在定义thread-local变量时更好的进行初始化。之前你初始化变量时是这样的:
1
ThreadLocal<List<String>> strings = new ThreadLocal<List<String>>() { @Override protectedList<String> initialValue() { return new ArrayList<>();
2
}
3
};
现在则是这样:
1
ThreadLocal<List<String>> strings =
2
ThreadLocal.withInital(ArrayList::new);
stream的API的返回值有一个可选的<T>,就像min/max, findFirst/Any, 以及reduce的某些形式。这样做是因为stream中可能没有任何元素,但是它要提供一个一致的API,既可以处理“一些结果”,也可以处理“没有结果”。你可以提供默认值,抛异常,或者只在有结果的时候执行一些动作。
它与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
people.sort(Comparators.comparing(Person::getLastName)
2
.thenComparing(Person::getFirstName));
这些新增功能提供了良好的,复杂的各种可读的简写。大多数用例由JDK里增加的 ComparisonChain和Ordering工具类来提供服务。对于什么是有价值的,我认为JDK版本比在Guava-ese里功能等效的版本的可读性好了很多。