Java 8 新特性介紹
新特性分類
- 語言功能增加特性
- API 類庫
- 平臺和虛擬機
- 周邊工具
語言功能增加特性
- 函數(shù)式接口
- lambda表達式
- 方法引用
- 接口(interface)的改進
類庫
- 集合庫的Lambda增強
- 并行集合操作
- 流API
- 日期時間API
- 網(wǎng)絡
- 安全
- IO
JVM和平臺
- Nashorn JavaScript Engine
- Reduce Cache Contention on Specified Fields
- Remove the Permanent Generation
- Retire Some Rarely-Used GC Combinations
- Fence Intrinsics
- Reduce Class Metadata Footprint
- Enhanced Verification Errors
周邊工具
- DocTree API
- DocLint
- Access to Parameter Names at Runtime
- Repeating Annotations
- Enhance javac to Improve Build Speed
新特性介紹
函數(shù)式接口 FunctionalInterface
所謂函數(shù)式接口是只有一個抽象方法的接口
函數(shù)式接口實例 @FunctionalInterface注解
只要接口定義滿足函數(shù)式接口 無論接口是否加上@FunctionalInterface注解 編譯器都認為是函數(shù)式接口
函數(shù)式接口四條規(guī)則
- 接口只能定義一個抽象方法
- 覆蓋Object類的抽象方法不算抽象方法里
- 注解@FunctionalInterface 只能用在接口上
- 如果滿足函數(shù)式接口 無論是否使用@FunctionalInterface注解 編譯器都認為是函數(shù)式接口
JDK一些常用函數(shù)式接口
java.lang.Runnable
java.io.FileFilter
java.io.FilenameFilter
java.util.Comparator
java.util.concurrent.Callable
lambda表達式
冗長無意義的代碼
** 一個簡單的線程例子 **
//使用匿名內(nèi)部類寫一個線程方法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}).start();
//小寫轉(zhuǎn)大寫
List<String> nameList = Arrays.asList("a","b","c");
List<String> upperNameList = new ArrayList<String>();
for(String name : nameList){
upperNameList.add(name.toLowerCase());
}
** 寫代碼能簡單一點嗎?**
可以
// 使用lambda表達式
new Thread(
() -> System.out.println(Thread.currentThread().getName())
).start();
//使用流操作
nameList.stream().map(str -> str.toUpperCase());
Lambda表達式一般形式
//求和lambda表達式
(int x, int y) -> {return x + y;}
(String s) -> {System.out.println(s)};
list -> {list.add(42); return list;}
lambda表達式內(nèi)可以訪問外部變量
// Java 8 以前 i 必須用final修飾
int i = 0;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(i);
// i = 1; 都不能對i進行賦值
}
});
int j = 1;
new Thread(() -> {
System.out.println(j);
// j = 1;不能對j進行賦值 官方名稱為"effectively final"
});
** effectively final **
目標類型 target type
lambda表達式是什么?
比如 x -> x * 2 是函數(shù)式接口 interface IntOperation { int operate(int i); }
的一個實例
IntOperation twice = x -> x * 2;
IntOperation square = x -> x * x;
System.out.println(twice.operate(3));
System.out.println(square.operate(3));
// lambda必須是函數(shù)式接口實例
// Object o = x -> System.out.println(x);
Consumer<?> c = x -> System.out.println(x);
Object o = c;
作用域和上下文
public class WhatIsThis {
void checkThis() {
System.out.println("outer " + this);
new Thread(new Runnable() {
public void run() {
System.out.println("inner " + this);
printThis();
}
}).start();
new Thread(() -> {
System.out.println("in lambda " + this);
}).start();
}
void printThis() {
System.out.println("from printThis() " + this);
}
public static void main(String[] args) {
new WhatIsThis().checkThis();
}
}
方法引用
編程語言內(nèi)各種方法抽象出來作為一個變量類型迂猴,作為參數(shù)輸入彻况,或者做為返回值返回
通過方法引用實現(xiàn)函數(shù)式編程語言的function as first-classs object(函數(shù)作為一等公民) 方法可以像變量一樣做為參數(shù)或返回值
例子一
//字符串小寫轉(zhuǎn)大寫
Function<String, String> upperfier = String::toUpperCase;
System.out.println(upperfier.apply("Hello"));
** 例子二 **
//集合元素判斷
Set<String> knowNames = new HashSet<>();
knowNames.add("Zhang");
knowNames.contains("Zhang");
Predicate<String> isKnowName = knowNames::contains;
isKnowName.test("Zhang");
isKnowName.test("Li");
方法引用類型有
| 類型 | 使用方法 | lambda形式 |
| --- | --- |
| 實例方法 | x::toString | () -> x.toString() |
| 靜態(tài)方法 | String::valueOf | x -> x.toString() |
| 構(gòu)造方法 | ArrayList::new | () -> new ArrayList<>() |
| 數(shù)組構(gòu)造方法 | EleType[]::new |
JDK對方法的的抽象(輸入輸出抽象) 在java.util.function包下
// 輸入類型為T輸出為R
public interface Function<T, R>{
R apply(T t);
}
//輸出布爾值
public interface Predicate<T>{
boolean test(T t);
}
// 沒有輸入 輸出為T
public interface Supplier<T> {
T get();
}
// 輸入為類型T 沒有輸出
public interface Consumer<T> {
void accept(T t);
}
方法引用與lambda表達式的等價關系
接口的改進
接口允許有實現(xiàn)方法
virtual extension method
default 關鍵字來修飾實現(xiàn)方法
default public void printOrderInfo(String orderId){
System.out.println(orderId);
}
接口允許有靜態(tài)方法
public interface InterfaceStaticMethod {
static void myMethod(){
System.out.println("myMethod");
}
}
// Comparator接口生成比較器方法
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
//根據(jù)名字做比較的比較器
Comparator nameComparator = Comparator.comparing(Employee::getName);
//根據(jù)薪水做比較比較器
Comparator salaryComparator = Comparator.comparing(Employee::getSalary);
接口多繼承問題
- 繼承多個具有相同的方法接口 必須在子接口方法里明確指定調(diào)用哪個父接口的方法
- 實現(xiàn)接口的類也同理
interface SubInterface extends MyInterface1,MyInferface2{
@Override
default void test(String str) {
MyInferface2.super.test(str);
}
}
class SubClass implements MyInterface1,MyInferface2{
@Override
public void test(String str) {
MyInterface1.super.test(str);
}
}
類型推導
所謂類型推導編譯器根據(jù)上下文 智能的推斷變量的類型,不需要開發(fā)者顯式指定變量類型
- java 7 對范型類型推導改進
Map<String, Object> map2 = new HashMap<String, Object>();
// 右邊括號內(nèi)<>參數(shù)類型可以省略
Map<String, Object> map1 = new HashMap<>();
官方叫做diamond
lambda表達式智能推導參數(shù)類型
Comparator<String> comparator = (String str1,String str2) -> {
return str1.compareTo(str2);
};
// 不需要顯式指定str1和str2的類型為String
Comparator<String> comparator2 = (str1,str2) -> {
return str1.compareTo(str2);
};
類型推導上下文范圍
- Variable declarations
- Assignments
- Return statements
- Array initializers
- Method or constructor arguments
- Lambda expression bodies
- Conditional expressions, ?:
- Cast expressions
新特性花式組合完法
- 比較器的N種寫法
代碼例子
類庫
集合庫的Lambda增強
- Collection新增方法
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)
并行集合操作
集合的塊數(shù)據(jù)操作
流API
** Stream的本質(zhì)是對數(shù)據(jù)源進行抽象 提供一套通用API對數(shù)據(jù)源操作 **
引入Stream谈秫、函數(shù)式接口抚岗、lambda等幾大特性java 8 有了一些函數(shù)式編程語言味道
Stream實現(xiàn)map filter reduce等操作或杠,Stream的數(shù)據(jù)源包括數(shù)組、集合宣蔚、IO通道向抢、隨機數(shù)生成器等,Stream相關接口在java.util.stream包下
public interface Stream<T> extends BaseStream<T, Stream<T>> {
//過濾
Stream<T> filter(Predicate<? super T> predicate);
// 映射
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
//聚合
T reduce(T identity, BinaryOperator<T> accumulator);
}
Stream接口方法分類
Intermediate 輸出還是stream认境,比如filter,map
Terminal 對流的聚合操作比如 sum count等
對流操作的一般過程
- 從數(shù)據(jù)源獲取流
- 執(zhí)行一個或多個中間操作
3 執(zhí)行一個終結(jié)操作(terminal operation)
//對list求和
int result = list.stream().reduce(0,(x,y) -> x + y);
//對list過濾(大于5的數(shù)字)再求和
int result = list.stream().filter(x -> x > 5).reduce(0,(x,y) -> x + y);
//對list 過濾(大于5的數(shù)字) 映射(求平方) 再求和,先通過mapToInt生成IntStream挟鸠,調(diào)用sum方法
result = list.stream().filter(x -> x > 5).map(x -> x * x).mapToInt(x -> x).sum();
各位腦補下寫代碼過程中如果用Stream的map filter reduce來簡化代碼
流的延遲初始化特性lazy
數(shù)字流
IntStream
LongStream
DoubleStream
可以對數(shù)字流進行sum, min, max,average等聚合操作
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>
Unix下的管道叉信?
玩轉(zhuǎn)Stream之數(shù)據(jù)庫SQL
http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html
流與集合比較
Stream輔助類Collector
日期時間API
新的java.time包
Instant——代表的是時間戳
LocalDate——日期(不帶時間)比如2016-10-29。它可以用來存儲生日艘希,周年紀念日硼身,入職日期等,
LocalTime——它代表的是不含日期的時間
LocalDateTime——它包含了日期及時間覆享,不過還是沒有偏移信息或者說時區(qū)佳遂。
ZonedDateTime——這是一個包含時區(qū)的完整的日期時間,偏移量是以UTC/格林威治時間為基準的撒顿。
枚舉類
DayOfWeek
Month
網(wǎng)絡
安全
JVM和平臺
周邊工具
----------參考資料-----------------
Oracle 官方 Java8新特性
Open JDK feature list
關于java lambda表達式一切問題