改進接口
現在可以在接口中定義靜態方法了。例如,java.util.Comparator接口中現在擁有一個靜態的naturalOrder方法。
public static > Comparator naturalOrder() {
return (Comparator) Cmparators.NaturalOrderComparator.INSTANCE;
}
還能夠在接口中提供默認方法。通過該功能,程序員能夠在不破壞已有的接口實現代碼的前提下添加新方法。例如,java.lang.Iterable接口現在擁有一個默認的forEach方法。
public default void forEach(Consumer 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作為輸出
Predicate——將T作為輸入,返回一個布爾值作為輸出
Consumer——將T作為輸入,不返回任何內容
Supplier——沒有輸入,返回T
BinaryOperator——將兩個T作為輸入,返回一個T作為輸出
java.util.stream
新的 java.util.stream包提供了對值流進行函數式操作的類。從一個集合中獲取流的一種常見方式是:
Stream 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.bar());
Utility.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 8還向很多其他的包中添加了大量其他的功能,在本文中我們并沒有提及。下面是一些值得注意的內容。可以使用ThreadLocal.withInitial(Supplier)更加簡潔的聲明本地線程變量。長期未兌現的StringJoiner和String.join(...)現在已經是Java 8的一部分了。比較器提供了一些新的方法能夠用于鏈接和基于域的比較。默認的字符串池映射大小更大了,大約在25—50K。