速度更快java
代碼更少(增長了新的語法 Lambda 表達式)sql
強大的 Stream API數據庫
便於並行數組
最大化減小空指針異常 Optional網絡
其中最爲核心的爲 Lambda 表達式與Stream APIapp
Lambda 是一個匿名函數,咱們能夠把 Lambda 表達式理解爲是一段能夠傳遞的代碼(將代碼像數據同樣進行傳遞)。能夠寫出更簡潔、更靈活的代碼。做爲一種更緊湊的代碼風格,使Java的語言表達能力獲得了提高。框架
從匿名類到 Lambda 的轉換ide
Lambda 表達式語法函數
左側:指定了 Lambda 表達式須要的全部參數性能
右側:指定了 Lambda 體,即 Lambda 表達式要執行的功能。
語法格式一:無參,無返回值,Lambda 體只需一條語句
語法格式二:Lambda 須要一個參數
語法格式三:Lambda 只須要一個參數時,參數的小括號能夠省略
語法格式四:Lambda 須要兩個參數,而且有返回值
語法格式五:當 Lambda 體只有一條語句時,return 與大括號能夠省略
類型推斷
什麼是函數式接口
只包含一個抽象方法的接口,稱爲函數式接口。
你能夠經過 Lambda 表達式來建立該接口的對象。(若 Lambda 表達式拋出一個受檢異常,那麼該異常須要在目標接口的抽象方 法上進行聲明)。
咱們能夠在任意函數式接口上使用 @FunctionalInterface 註解, 這樣作能夠檢查它是不是一個函數式接口,同時 javadoc 也會包含一條聲明,說明這個接口是一個函數式接口。
自定義函數式接口
函數式接口中使用泛型:
做爲參數傳遞 Lambda 表達式
做爲參數傳遞 Lambda 表達式:爲了將 Lambda 表達式做爲參數傳遞,接收Lambda 表達式的參數類型必須是與該 Lambda 表達式兼容的函數式接口的類型。
Java 內置四大核心函數式接口
函數式接口 |
參數類型 |
返回類型 |
用途 |
Consumer<T> 消費型接口 |
T |
void |
對類型爲T的對象應用操做,包含方法: void accept(T t) |
Supplier<T> 供給型接口 |
無 |
T |
返回類型爲T的對象,包含方法:T get(); |
Function<T, R> 函數型接口 |
T |
R |
對類型爲T的對象應用操做,並返回結果。結果是R類型的對象。包含方法:R apply(T t); |
Predicate<T> 判定型接口 |
T |
boolean |
肯定類型爲T的對象是否知足某約束,並返回boolean 值。包含方法boolean test(T t); |
其餘接口
函數式接口 |
參數類型 |
返回類型 |
用途 |
BiFunction<T, U, R> |
T, U |
R |
對類型爲 T, U 參數應用操做, 返回 R 類型的結果。包含方法爲 R apply(T t, U u); |
UnaryOperator<T> (Function子接口) |
T |
T |
對類型爲T 的對象進行一元運算, 並返回T 類型的結果。包含方法爲 T apply(T t); |
BinaryOperator<T> (BiFunction 子接口) |
T, T |
T |
對類型爲T 的對象進行二元運算, 並返回T類型的結果。包含方法爲 T apply(T t1, T t2); |
BiConsumer<T, U> |
T, U |
void |
對類型爲T, U 參數應用操做。包含方法爲 void accept(T t, U u) |
ToIntFunction<T> ToLongFunction<T> ToDoubleFunction<T> |
T |
int long double |
分 別 計 算 int 、 long 、 double、值的函數 |
IntFunction<R> LongFunction<R> DoubleFunction<R> |
int long double |
R |
參數分別爲int 、long 、 double 類型的函數 |
方法引用
當要傳遞給Lambda體的操做,已經有實現的方法了,可使用方法引用!(實現抽象方法的參數列表,必須與方法引用方法的參數列表保持一致!)
方法引用:使用操做符 「::」 將方法名和對象或類的名字分隔開來。
以下三種主要使用狀況:
對象::實例方法
類::靜態方法
類::實例方法
方法引用
等同於:
例如:
等同於:
例如:
等同於:
注意:當須要引用方法的第一個參數是調用對象,而且第二個參數是須要引用方法的第二個參數(或無參數)時:ClassName::methodName
構造器引用
等同於:
數組引用
格式: type[] :: new
瞭解 Stream
Java8中有兩大最爲重要的改變。第一個是 Lambda 表達式;另一個則是 Stream API(java.util.stream.*)。
Stream 是 Java8 中處理集合的關鍵抽象概念,它能夠指定你但願對集合進行的操做,能夠執行很是複雜的查找、過濾和映射數據等操做。 使用Stream API 對集合數據進行操做,就相似於使用 SQL 執行的數據庫查詢。也可使用 Stream API 來並行執行操做。簡而言之, Stream API 提供了一種高效且易於使用的處理數據的方式。
什麼是 Stream
是數據渠道,用於操做數據源(集合、數組等)所生成的元素序列。
「集合講的是數據,流講的是計算!」
注意:
①Stream 本身不會存儲元素。
②Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream。
③Stream 操做是延遲執行的。這意味着他們會等到須要結果的時候才執行。
Stream 的操做三個步驟
建立 Stream
一個數據源(如:集合、數組),獲取一個流
一箇中間操做鏈,對數據源的數據進行處理
一個終止操做,執行中間操做鏈,併產生結果
建立 Stream
default Stream<E> stream() : 返回一個順序流
default Stream<E> parallelStream() : 返回一個並行流
由數組建立流
Java8 中的 Arrays 的靜態方法 stream() 能夠獲取數組流:
static <T> Stream<T> stream(T[] array): 返回一個流
重載形式,可以處理對應基本類型的數組:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
由值建立流
可使用靜態方法 Stream.of(), 經過顯示值建立一個流。它能夠接收任意數量的參數。
public static<T> Stream<T> of(T... values) : 返回一個流
由函數建立流:
建立無限流
可使用靜態方法 Stream.iterate() 和Stream.generate(), 建立無限流。
迭代
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
生成
public static<T> Stream<T> generate(Supplier<T> s) :
Stream 的中間操做
多箇中間操做能夠鏈接起來造成一個流水線,除非流水 線上觸發終止操做,不然中間操做不會執行任何的處理! 而在終止操做時一次性所有處理,稱爲「惰性求值」。
篩選與切片
方 法 |
描 述 |
filter(Predicate p) |
接收 Lambda , 從流中排除某些元素。 |
distinct() |
篩選,經過流所生成元素的 hashCode() 和 equals() 去除重複元素 |
limit(long maxSize) |
截斷流,使其元素不超過給定數量。 |
skip(long n) |
跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。與 limit(n) 互補 |
Stream 的中間操做
方 法 |
描 述 |
map(Function f) |
接收一個函數做爲參數,該函數會被應用到每一個元素上,並將其映射成一個新的元素。 |
mapToDouble(ToDoubleFunction f) |
接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新DoubleStream。 |
mapToInt(ToIntFunction f) |
接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新的 IntStream。 |
mapToLong(ToLongFunction f) |
接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新的LongStream。 |
flatMap(Function f) |
接收一個函數做爲參數,將流中的每一個值都換成另外一個流,而後把全部流鏈接成一個流 |
Stream 的中間操做
方 法 |
描 述 |
sorted() |
產生一個新流,其中按天然順序排序 |
sorted(Comparator comp) | 產生一個新流,其中按比較器順序排序 |
Stream 的終止操做
查找與匹配
方 法 |
描 述 |
allMatch(Predicate p) |
檢查是否匹配全部元素 |
anyMatch(Predicate p) |
檢查是否至少匹配一個元素 |
noneMatch(Predicate p) |
檢查是否沒有匹配全部元素 |
findFirst() |
返回第一個元素 |
findAny() |
返回當前流中的任意元素 |
Stream 的終止操做
count() |
返回流中元素總數 |
max(Comparator c) |
返回流中最大值 |
min(Comparator c) |
返回流中最小值 |
forEach(Consumer c) |
內部迭代(使用 Collection 接口須要用戶去作迭代,稱爲外部迭代。相反,Stream API 使用內部迭代——它幫你把迭代作了) |
reduce(T iden, BinaryOperator b) |
能夠將流中元素反覆結合起來,獲得一個值。返回 T |
reduce(BinaryOperator b) |
能夠將流中元素反覆結合起來,獲得一個值。返回 Optional<T> |
備註:map 和 reduce 的鏈接一般稱爲 map-reduce 模式,因 Google 用它來進行網絡搜索而出名。
Stream 的終止操做
方 法 |
描 述 |
collect(Collector c) |
將流轉換爲其餘形式。接收一個 Collector接口的實現,用於給Stream中元素作彙總的方法 |
Collector 接口中方法的實現決定了如何對流執行收集操做(如收集到 List、Set、Map)。可是 Collectors 實用類提供了不少靜態方法,能夠方便地建立常見收集器實例,具體方法與實例以下表:
方法 |
返回類型 |
做用 |
toList |
List<T> |
把流中元素收集到List |
List<Employee> emps= list.stream().collect(Collectors.toList()); |
||
toSet |
Set<T> |
把流中元素收集到Set |
Set<Employee> emps= list.stream().collect(Collectors.toSet()); |
||
toCollection |
Collection<T> |
把流中元素收集到建立的集合 |
Collection<Employee>emps=list.stream().collect(Collectors.toCollection(ArrayList::new)); |
||
counting |
Long |
計算流中元素的個數 |
long count = list.stream().collect(Collectors.counting()); |
||
summingInt |
Integer |
對流中元素的整數屬性求和 |
inttotal=list.stream().collect(Collectors.summingInt(Employee::getSalary)); |
||
averagingInt |
Double |
計算流中元素Integer屬性的平均 值 |
doubleavg= list.stream().collect(Collectors.averagingInt(Employee::getSalary)); |
||
summarizingInt |
IntSummaryStatistics |
收集流中Integer屬性的統計值。 如:平均值 |
IntSummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary)); |
joining |
String |
鏈接流中每一個字符串 |
String str= list.stream().map(Employee::getName).collect(Collectors.joining()); |
||
maxBy |
Optional<T> |
根據比較器選擇最大值 |
Optional<Emp>max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary))); |
||
minBy |
Optional<T> |
根據比較器選擇最小值 |
Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary))); |
||
reducing |
歸約產生的類型 |
從一個做爲累加器的初始值開始,利用BinaryOperator與流中元素逐個結合,從而歸 約成單個值 |
inttotal=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum)); |
||
collectingAndThen |
轉換函數返回的類型 |
包裹另外一個收集器,對其結 果轉換函數 |
inthow= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size)); |
||
groupingBy |
Map<K, List<T>> |
根據某屬性值對流分組,屬 性爲K,結果爲V |
Map<Emp.Status, List<Emp>> map= list.stream() .collect(Collectors.groupingBy(Employee::getStatus)); |
||
partitioningBy |
Map<Boolean, List<T>> |
根據true或false進行分區 |
Map<Boolean,List<Emp>>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage)); |
並行流與串行流
別處理每一個數據塊的流。
Java 8 中將並行進行了優化,咱們能夠很容易的對數據進行並行操做。Stream API 能夠聲明性地經過 parallel() 與sequential() 在並行流與順序流之間進行切換。
瞭解 Fork/Join 框架
Fork/Join 框架:就是在必要的狀況下,將一個大任務,進行拆分(fork)成若干個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進行 join 彙總.
Fork/Join 框架與傳統線程池的區別
採用 「工做竊取」模式(work-stealing):
當執行新的任務時它能夠將其拆分分紅更小的任務執行,並將小任務加到線 程隊列中,而後再從一個隨機線程的隊列中偷一個並把它放在本身的隊列中。
相對於通常的線程池實現,fork/join框架的優點體如今對其中包含的任務的處理方式上.在通常的線程池中,若是一個線程正在執行的任務因爲某些緣由沒法繼續運行,那麼該線程會處於等待狀態.而在fork/join框架實現中,若是某個子問題因爲等待另一個子問題的完成而沒法繼續運行.那麼處理該子問題的線程會主動尋找其餘還沒有運行的子問題來執行.這種方式減小了線程的等待時間,提升了性能.
使用 LocalDate、LocalTime、LocalDateTime
LocalDate、LocalTime、LocalDateTime 類的實例是不可變的對象,分別表示使用 ISO-8601日曆系統的日期、時間、日期和時間。它們提供 了簡單的日期或時間,並不包含當前的時間信息。也不包含與時區相關的信息。
注:ISO-8601日曆系統是國際標準化組織制定的現代公民的日期和時間的表示法
方法 |
描述 |
示例 |
now() |
靜態方法,根據當前時間建立對象 |
LocalDate localDate = LocalDate.now(); LocalTime localTime = LocalTime.now(); LocalDateTime localDateTime = LocalDateTime.now(); |
of() |
靜態方法,根據指定日期/時間建立 對象 |
LocalDate localDate = LocalDate.of(2016, 10, 26); LocalTime localTime = LocalTime.of(02, 22, 56); LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55); |
plusDays, plusWeeks, plusMonths, plusYears |
向當前 LocalDate 對象添加幾天、幾周、幾個月、幾年 |
|
minusDays, minusWeeks, minusMonths, minusYears |
從當前 LocalDate 對象減去幾天、幾周、幾個月、幾年 |
|
plus, minus |
添加或減小一個 Duration 或 Period |
|
withDayOfMonth, withDayOfYear, withMonth, withYear |
將月份天數、年份天數、月份、年 份 修 改 爲 指 定 的 值 並 返 回 新 的 LocalDate 對象 |
|
getDayOfMonth |
得到月份天數(1-31) |
|
getDayOfYear |
得到年份天數(1-366) |
|
getDayOfWeek |
得到星期幾(返回一個 DayOfWeek 枚舉值) |
|
getMonth |
得到月份, 返回一個 Month 枚舉值 |
|
getMonthValue |
得到月份(1-12) |
|
getYear |
得到年份 |
|
until |
得到兩個日期之間的 Period 對象, 或者指定 ChronoUnits 的數字 |
|
isBefore, isAfter |
比較兩個 LocalDate |
|
isLeapYear |
判斷是不是閏年 |
|
Instant 時間戳
Duration 和 Period
Duration:用於計算兩個「時間」間隔
Period:用於計算兩個「日期」間隔
日期的操縱
TemporalAdjusters : 該類經過靜態方法提供了大量的經常使用 TemporalAdjuster 的實現。
例如獲取下個週日:
預約義的標準格式
語言環境相關的格式
自定義的格式
Java8 中加入了對時區的支持,帶時區的時間爲分別爲:
ZonedDate、ZonedTime、ZonedDateTime
其中每一個時區都對應着 ID,地區ID都爲 「{區域}/{城市}」的格式
例如 :Asia/Shanghai 等
ZoneId:該類中包含了全部的時區信息getAvailableZoneIds() : 能夠獲取全部時區時區信息of(id) : 用指定的時區信息獲取 ZoneId 對象
類 |
To 遺留類 |
From 遺留類 |
java.time.Instant java.util.Date |
Date.from(instant) |
date.toInstant() |
java.time.Instant java.sql.Timestamp |
Timestamp.from(instant) |
timestamp.toInstant() |
java.time.ZonedDateTime java.util.GregorianCalendar |
GregorianCalendar.from(zonedDateTim e) |
cal.toZonedDateTime() |
java.time.LocalDate java.sql.Time |
Date.valueOf(localDate) |
date.toLocalDate() |
java.time.LocalTime java.sql.Time |
Date.valueOf(localDate) |
date.toLocalTime() |
java.time.LocalDateTime java.sql.Timestamp |
Timestamp.valueOf(localDateTime) |
timestamp.toLocalDateTime() |
java.time.ZoneId java.util.TimeZone |
Timezone.getTimeZone(id) |
timeZone.toZoneId() |
java.time.format.DateTimeFormatter java.text.DateFormat |
formatter.toFormat() |
無 |
例如:
接口中的默認方法
接口默認方法的」類優先」原則
若一個接口中定義了一個默認方法,而另一個父類或接口中又定義了一個同名的方法時
選擇父類中的方法。若是一個父類提供了具體的實現,那麼接口中具備相同名稱和參數的默認方法會被忽略。
接口衝突。若是一個父接口提供一個默認方法,而另外一個接口也提供了一個具備相同名稱和參數列表的方法(無論方法是不是默認方法),那麼必須覆蓋該方法來解決衝突
接口中的靜態方法
Java8 中,接口中容許添加靜態方法。
例如:
Optional 類
Optional<T> 類(java.util.Optional) 是一個容器類,表明一個值存在或不存在, 原來用 null 表示一個值不存在,如今 Optional 能夠更好的表達這個概念。而且能夠避免空指針異常。
經常使用方法:
Optional.of(T t) : 建立一個 Optional 實例Optional.empty() : 建立一個空的 Optional 實例
Optional.ofNullable(T t):若 t 不爲 null,建立 Optional 實例,不然建立空實例isPresent() : 判斷是否包含值
orElse(T t) : 若是調用對象包含值,返回該值,不然返回t orElseGet(Supplier s) :若是調用對象包含值,返回該值,不然返回 s 獲取的值
map(Function f): 若是有值對其處理,並返回處理後的Optional,不然返回 Optional.empty()
flatMap(Function mapper):與 map 相似,要求返回值必須是Optional
重複註解與類型註解