一:接口上定义的方法可以存在方法体
二:支持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完全重写。内部看起来它一点不像是Java7版本。从外部来看几乎相同,除了它有大量批量操作方法:多种形式的减少搜索和forEach。
ConcurrentHashMap.newKeySet()提供了一个并发的java.util.Set实现。它基本上是Collections.newSetFromMap(new ConcurrentHashMap())的另一种方式的重写。StampedLock是一种新型锁的实现,很可能在大多数场景都可以替代ReentrantReadWriteLock。当作为一个简单的读写锁的时候,它比RRWL的性能要好。它也为“读优化”提供了API,通过它你获得了一个功能有点弱,但代价很小的读操作锁的版本,执行读操作,然后检查锁是否被一个写操作设定为无效。在Heinz Kabutz汇总的一系列幻灯片中,有更多关于这个类及其性能的细节(在这个系列幻灯片大约一半的地方开始的):"移相器和StampedLock演示"
CompletableFuture是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.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) 可以在定义thread-local变量时更好的进行初始化。之前你初始化变量时是这样的:
1
ThreadLocalString>> strings = new ThreadLocalString>>() { @Override protectedList<String> initialValue() { return new ArrayList<>();
2
}
3
};
现在则是这样:
1
ThreadLocalString>> strings =
2
ThreadLocal.withInital(ArrayList::new);
stream的API的返回值有一个可选的,就像min/max, findFirst/Any, 以及reduce的某些形式。这样做是因为stream中可能没有任何元素,但是它要提供一个一致的API,既可以处理“一些结果”,也可以处理“没有结果”。你可以提供默认值,抛异常,或者只在有结果的时候执行一些动作。
它与Guava
旁白:Java 8
"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里功能等效的版本的可读性好了很多。