Java8新特性

 

Java 8新特性簡介

  • 速度更快java

  • 代碼更少(增長了新的語法 Lambda 表達式)sql

  • 強大的 Stream API數據庫

  • 便於並行數組

  • 最大化減小空指針異常 Optional網絡

其中最爲核心的爲 Lambda 表達式與Stream APIapp

1 Lambda表達式

爲何使用  Lambda  表達式

Lambda 是一個匿名函數,咱們能夠把 Lambda 表達式理解爲是一段能夠傳遞的代碼(將代碼像數據同樣進行傳遞)。能夠寫出更簡潔、更靈活的代碼。做爲一種更緊湊的代碼風格,使Java的語言表達能力獲得了提高。框架

從匿名類到 Lambda 的轉換ide

 

Lambda 表達式語法函數

Lambda 表達式在Java 語言中引入了一個新的語法元素和操做符。這個操做符爲 「->」 , 該操做符被稱爲 Lambda 操做符或剪頭操做符。它將 Lambda 分爲兩個部分:

左側:指定了 Lambda 表達式須要的全部參數性能

右側:指定了 Lambda 體,即 Lambda 表達式要執行的功能。

語法格式一:無參,無返回值,Lambda 體只需一條語句

 

語法格式二:Lambda 須要一個參數

 

語法格式三:Lambda 只須要一個參數時,參數的小括號能夠省略

語法格式四:Lambda 須要兩個參數,而且有返回值

 

語法格式五:當 Lambda 體只有一條語句時,return 與大括號能夠省略

 

 

類型推斷

上述 Lambda 表達式中的參數類型都是由編譯器推斷得出的。Lambda 表達式中無需指定類型,程序依然能夠編譯,這是由於 javac 根據程序的上下文,在後臺推斷出了參數的類型。Lambda 表達式的類型依賴於上下文環境,是由編譯器推斷出來的。這就是所謂的   「類型推斷」。

函數式接口

什麼是函數式接口

只包含一個抽象方法的接口,稱爲函數式接口。

你能夠經過 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

構造器引用

格式: ClassName::new 

與函數式接口相結合,自動與函數式接口中方法兼容。 能夠把構造器引用賦值給定義的方法,與構造器參數列表要與接口中抽象方法的參數列表一致!

例如:

等同於:

數組引用

格式: type[] :: new

例 如 :
等同於:

強大的 Stream API

瞭解 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

一個數據源(如:集合、數組),獲取一個流

中間操做

一箇中間操做鏈,對數據源的數據進行處理

終止操做(終端操做)

一個終止操做,執行中間操做鏈,併產生結果

建立 Stream

Java8 中的 Collection 接口被擴展,提供了兩個獲取流的方法:

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 的終止操做

終端操做會從流的流水線生成結果。其結果能夠是任何不是流的值,例如:List、Integer,甚至是 void 。

查找與匹配

方 法

描 述

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框架實現中,若是某個子問題因爲等待另一個子問題的完成而沒法繼續運行.那麼處理該子問題的線程會主動尋找其餘還沒有運行的子問題來執行.這種方式減小了線程的等待時間,提升了性能.

新時間日期 API

使用 LocalDateLocalTimeLocalDateTime

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 時間戳

用於「時間戳」的運算。它是以Unix元年(傳統的設定爲UTC時區1970年1月1日午夜時分)開始所經歷的描述進行運算

Duration 和 Period

Duration:用於計算兩個「時間」間隔

Period:用於計算兩個「日期」間隔

日期的操縱

TemporalAdjuster : 時間校訂器。有時咱們可能須要獲取例如:將日期調整到「下個週日」等操做。

TemporalAdjusters : 該類經過靜態方法提供了大量的經常使用 TemporalAdjuster 的實現。

例如獲取下個週日:

 

解析與格式化

java.time.format.DateTimeFormatter 類:該類提供了三種格式化方法:

預約義的標準格式

語言環境相關的格式

自定義的格式

時區的處理

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()

接口中的默認方法與靜態方法

接口中的默認方法

Java 8中容許接口中包含具備具體實現的方法,該方法稱爲「默認方法」,默認方法使用 default 關鍵字修飾。

例如:

接口中的默認方法

接口默認方法的」類優先」原則

若一個接口中定義了一個默認方法,而另一個父類或接口中又定義了一個同名的方法時

選擇父類中的方法。若是一個父類提供了具體的實現,那麼接口中具備相同名稱和參數的默認方法會被忽略。

接口衝突。若是一個父接口提供一個默認方法,而另外一個接口也提供了一個具備相同名稱和參數列表的方法(無論方法是不是默認方法),那麼必須覆蓋該方法來解決衝突

接口中的靜態方法

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

重複註解與類型註解

Java 8對註解處理提供了兩點改進:可重複的註解及可用於類型的註解。

 

相關文章
相關標籤/搜索