java8新特性

????????????????????????java8新特性

????????????????????????原創(chuàng)者:文思

一、特性簡介

速度更快

代碼更少,增加了Lambda?????????

強大的Stream API

便于并行

最大化減少空指針異常

二、Lambda表達式

1、Lambda簡介

Lambda是一個匿名函數(shù),可以理解為一段可以傳遞的代碼。

Lambda解決了什么?

沒有Lambda之前,靠匿名內(nèi)部類解決的需求

package java8;

import java.util.ArrayList;

import java.util.Arrays;

importjava.util.Comparator;

import java.util.List;

importjava.util.TreeSet;

importcom.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader.Array;

public classTestLamabda {

??? Listlist= Arrays.asList(

?????????? new Employee("zhangsan",56,19999),

?????????? new Employee("lisi",36,169999),

?????????? new Employee("wangwu",66,369999));

??? public static void main(String[] args) {

?????? TestLamabdat = new TestLamabda();

?????? t.test();

??? }

??? public void test(){

?????? ListEmployees = getList(list,newFilterEmployeeInterface<Employee>(){

?????????? @Override

?????????? public boolean test(Employee t) {

????????????? return t.getSalary()>19999;

?????????? }


?????? });

?????? for(Employee e:Employees){

?????????? System.out.println(e);

?????? }

??? }

??? public List<Employee>

getList(List<Employee> list,FilterEmployeeInterfaceemp){

?????? ListempList= newArrayList<Employee>();

?????? for(Employee e:this.list){

?????????? if(emp.test(e)){

????????????? empList.add(e);

?????????? }

?????? }

?????? return empList;

??? }

}

運行輸出:

java8.Employee@15db9742

java8.Employee@6d06d69c

而用Lambda表達式:

publicListgetList(Listlist,FilterEmployeeInterfaceemp){

?????? ListempList = newArrayList();

?????? for(Employee e:this.list){

?????????? if(emp.test(e)){

????????????? empList.add(e);

?????????? }

?????? }

?????? return empList;

??? }

??? public void test1(){

?????? ListempList = getList(list,(e)->((Employee)e).getSalary()>5619999);

?????? list.forEach(System.out::println);

??? }

2、Lambda表達式

->左側(cè):表達式的參數(shù)列表。接口中抽象方法的的形參

->右側(cè):表達式中所需執(zhí)行的功能。接口中抽象方法的實現(xiàn)

語法格式1:無參數(shù)無返回值

() -> System.out.println();

語法格式2:有參數(shù)無返回值

() -> System.out.println(e);

語法格式3:若只有一個參數(shù),小括號可以不寫

語法格式4:有兩個以上參數(shù),有返回值

Comparator<Integer> com = (x,y)->{….;….

}

Lambda表達式需要函數(shù)式接口的支持。

三、函數(shù)式接口

什么是函數(shù)式接口?

只包含一個抽象方法的接口,稱為函數(shù)式接口。

可以通過Lambda 表達式來創(chuàng)建該接口的對象。(若Lambda 表達式拋出一個受檢異常,那么該異常需要在目標(biāo)接口的抽象方法上進行聲明)

我們可以在任意函數(shù)式接口上使用@FunctionalInterface注解,這樣做可以檢查它是否是一個函數(shù)式接口,同時javadoc也會包含一條聲明,說明這個接口是一個函數(shù)式接口。

自定義函數(shù)式接口:

@FunctionalInterface

public interfaceMyFunctionInterface<T> {

??? public T getValue(T t);

}

package java8;

import java.util.ArrayList;

import java.util.List;

import java.util.function.Consumer;

import java.util.function.Function;

import java.util.function.Predicate;

import java.util.function.Supplier;

/**

?* java8內(nèi)置的四大核心函數(shù)式接口

?*

?*Consumer<T>:消費型接口

?*???? void accept(T t)

?*Supplier<T>:供給型接口

?*???? T get()

?*Function:函數(shù)型接口

?*???? Rapply(T t)

?*Predicate<T>:斷言型接口

?*???? booleantest(T t)

?*/

public class?TestLambda3 {

??? //消費類型接口

??? public void xiaofei(double money,Consumer<Double> con){

?????? con.accept(money);

??? }

??? public void test1(){

?????? xiaofei(10000,(m) -> System.out.println("旅游消費:"+m+"元"));

??? }

??? //供給類型接口

??? public List<Integer> getNumList(intnum,Supplier<Integer>sup){

?????? List?list = new?ArrayList<Integer>();

?????? for(int i=0;i<num;i++){

?????????? Integer n = sup.get();

?????????? list.add(n);

?????? }

?????? return list;

??? }

??? public void test2(){

List<Integer>list= getNumList(10,()->(int)(Math.random()*100));

?????? for(Integer i:list){

?????????? System.out.print(i+",");

?????? }

?????? System.out.println();

??? }

??? //函數(shù)型接口

??? public String strHandler(String str,Function<String,String>fun){?

?????? return fun.apply(str);

??? }

??? public void test3(){

?????? String newStr = strHandler("acb",(str) -> str.toUpperCase());

?????? System.out.println(newStr+",");

??? }

??? //斷言型

??? public boolean isTest(String str,Predicate<String>pre){

?????? return pre.test(str);

??? }

??? public void test4(){

?????? boolean f = isTest("is",(m)->m.equals("is"));

?????? if(f){

?????????? System.out.println(f);

?????? }

??? }

??? public static void main(String[] args) {

?????? System.out.println("消費型:");

?????? new TestLambda3().test1();

?????? System.out.println("供給型:");

?????? new TestLambda3().test2();

?????? System.out.println("函數(shù)型:");

?????? new TestLambda3().test3();

?????? System.out.println("斷言型:");

?????? newTestLambda3().test4();?

?????? System.out.println("自定義:");

?????? new TestLambda3().test5();

??? }

??? //自定義供給型接口

public Integer testCusomerFunctionInterface(Integer i,MyFunctionInterface<Integer> customerFun ){

?????? return customerFun.getValue(i);

??? }

??? public void test5(){

?????? Integeri = testCusomerFunctionInterface(1,(m)->(m+1));

?????? System.out.println(i);

??? }

}

運行輸出:

消費型:

旅游消費:10000.0元

消費型:

旅游消費:10000.0元

供給型:

76,62,27,7,25,83,18,69,19,5,

函數(shù)型:

ACB,

斷言型:

true

自定義:

2

作為參數(shù)傳遞Lambda 表達式:為了將Lambda 表達式作為參數(shù)傳遞,接收Lambda 表達式的參數(shù)類型必須是與該Lambda 表達式兼容的函數(shù)式接口的類型。

其它子接口:


四、方法引用與構(gòu)造器引用

package java8;

import java.io.PrintStream;

import java.util.Comparator;

import java.util.function.BiPredicate;

import java.util.function.Consumer;

import java.util.function.Supplier;

/*

?*一、方法引用:若 Lambda 體中的功能,已經(jīng)有方法提供了實現(xiàn),可使用方法引用

?*??????? ??(可以將方法引用理解為 Lambda 表達式的另外一種表現(xiàn)形式)


?* 1.對象的引用 :: 實例方法名

?* 2.類名 :: 靜態(tài)方法名

?* 3.類名 :: 實例方法名

?*注意:

?* ?①方法引用所引用的方法的參數(shù)列表與返回值類型,需要與函數(shù)式接口中抽象方法的參數(shù)列表和返回值類型保持一致!

?* ?②若Lambda 的參數(shù)列表的第一個參數(shù),是實例方法的調(diào)用者,第二個參數(shù)(或無參)是實例方法的參數(shù)時,格式: ClassName::MethodName

?*二、構(gòu)造器引用 :構(gòu)造器的參數(shù)列表,需要與函數(shù)式接口中參數(shù)列表保持一致!

?* 1.類名 :: new

?*三、數(shù)組引用

?* 類型[] :: new;

?*/

public classTestMethodRef {

??? //對象::實例方法名

??? public void test1(){

?????? PrintStream ps = System.out;

?????? Consumer?con1= ps::println;

?????? con1.accept("abc");

??? }

??? //類::靜態(tài)方法

??? public void test2(){

?????? Comparator?com = Integer::compare;

??? }

??? //類::實例方法名。(如果第一個參數(shù)是實例方法的調(diào)用者,且第二個參數(shù)是實例方法的參數(shù)時才能使用)

??? public void test3(){

??? //? BiPredicate?bp = (x,y)->x.equals(y);????

?????? BiPredicate?bp = String::equals;

??? }

??? //構(gòu)造器引用

??? public void test4(){

??? //? Suppliersup = ()->new Employee();

?????? Supplier?sup = Employee::new;

?????? Employee emp = sup.get();

?????? System.out.println(emp);

??? }

}

五、Stream API

此流非彼流

Java8中有兩大最為重要的改變。第一個是Lambda 表達式;另外一個則是Stream API(java.util.stream.*)。

Stream 是Java8 中處理集合的關(guān)鍵抽象概念,它可以指定你希望對集合進行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作。使用Stream API 對集合數(shù)據(jù)進行操作,就類似于使用SQL 執(zhí)行的數(shù)據(jù)庫查詢。也可以使用Stream API 來并行執(zhí)行操作。簡而言之,Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。

流(Stream) 到底是什么呢?

是數(shù)據(jù)渠道,用于操作數(shù)據(jù)源(集合、數(shù)組等)所生成的元素序列?!凹现v的是數(shù)據(jù),流講的是計算!”

注意:

①Stream 自己不會存儲元素。

②Stream 不會改變源對象。相反,他們會返回一個持有結(jié)果的新Stream。

③Stream 操作是延遲執(zhí)行的。這意味著他們會等到需要結(jié)果的時候才執(zhí)行

Stream 的操作三個步驟:

創(chuàng)建Stream一個數(shù)據(jù)源(如:集合、數(shù)組),獲取一個流中間操作

一個中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進行處理終止操作(終端操作)

一個終止操作,執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果

package java8;


import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

/*

?*一、Stream API 的操作步驟:

?* 1.創(chuàng)建 Stream

?* 2.中間操作

?* 3.終止操作(終端操作)

?*/

public classTestSteamAPI {

??? public void test(){

?????? //1、可以通過Collection系列集合提供的stream()或parallStream()

?????? Listlist= newArrayList<>();

?????? Streamstream= list.stream();

?????? //2通過Arrays中的靜態(tài)方法stream()獲取

?????? Employee[]emps= newEmployee[10];

?????? Streamstream1= Arrays.stream(emps);

?????? //3通過Stream類中的靜態(tài)方法of()

?????? Streamstream2= Stream.of("a","b","c");

?????? //4創(chuàng)建無限流

?????? Streamstream3= Stream.iterate(1,(x->x+2));

?????? stream3.limit(10).forEach(System.out::println);

??? }

}

Stream的中間操作

多個中間操作可以連接起來形成一個流水線,除非流水線上觸發(fā)終止操作,否則中間操作不會執(zhí)行任何的處理!

而在終止操作時一次性全部處理,稱為“惰性求值”。

篩選與切片:

映射:

排序:

importjava.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

public classTestStreamAPI2 {

??? List?list = Arrays.asList(

?????????? new Employee("zhangsan",56,19999),

?????????? new Employee("lisi",36,169999),

?????????? new Employee("wangwu",66,369999));

??? /**

??? ?*中間操作

??? ?*/

??? //filter舉例

??? public void test1(){

?????? //中間操作:每次循環(huán)不會執(zhí)行任何操作

?????? Stream?es = list.stream().filter((e)->

?????????? {

????????????? System.out.print("fasfa");

????????????? return e.getAge()>30;

?????????? });

?????? //終止操作:一次執(zhí)行全部內(nèi)容(惰性求值)

?????? es.forEach(System.out::println);

??? }

??? //skip舉例

??? public void test2(){

?????? list.stream().filter((e)->{

?????????? return e.getAge()>30;

?????? }).skip(2).forEach(System.out::println);

??? }

??? //映射,map-接收lambda,將元素轉(zhuǎn)換成其它形式或提取信息。并接收一個函數(shù)作為參數(shù),該函數(shù)會作用于每一個元素上

public void?test3(){???????

?????list.stream().map((e)->e.getName().toUpperCase()).forEach(System.out::println);?????????

? ?}

??? //flatMap針對Stream<Stream>,Stream嵌套Stream這種情況

??? public void test4(){

?????? /* Stream<Stream<String>> stream

?????? ?* stream.forEach((sm)->{sm.forEach(System.out::println)})

?????? ?*/

??? }

??? //排序,sorted()自然排序,sorted(Comparatorcom)定制排序

??? public void test5(){

?????? list.stream().sorted((e,ee)->{

?????????? if(e.getAge()>ee.getAge()){

????????????? return e.getName().compareTo(ee.getName());

?????????? }else{

????????????? return e.getName().compareTo(ee.getName());

?????????? }

?????? }).forEach(System.out::println);

??? }

}

查找與匹配:

規(guī)約:

收集:

Collector接口中方法的實現(xiàn)決定了如何對流執(zhí)行收集操作(如收集到List、Set、Map)。但是Collectors 實用類提供了很多靜態(tài)方法,可以方便地創(chuàng)建常見收集器實例,具體方法與實例:

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

import java.util.stream.Collectors;

import org.junit.Test;

public classTestStreamAPI3 {

??? List<employees> employeesList= Arrays.asList(

?????????? new Employee("zhangsan",56,19999),

?????????? new Employee("lisi",36,169999),

?????????? new Employee("wangwu",66,369999));

??? //規(guī)約:reduce(T identity,BinaryOperator)/reduce(BinaryOperator)

??? //可以將流中元素反復(fù)結(jié)合起來得到一個值

??? @Test

??? public void test(){

?????? List?list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

?????? Integer sum = list.stream().reduce(0,(x,y)->x+y);

?????? System.out.println(sum);


?????? Optional?op = employeesList.stream()

????????????? .map((e)->e.getAge())

????????????? .reduce(Integer::sum);

?????? System.out.println(op.get());

??? }

??? //收集:collect將流轉(zhuǎn)換為其它形式。接收一個Collector接口的實現(xiàn),用于給Stream元素做匯總的方法

??? @Test

??? public void test1(){

?????? List?list = employeesList.stream().map(Employee::getName).collect(Collectors.toList());

?????? list.forEach(System.out::println);


?????? Long count = employeesList.stream().collect(Collectors.counting());

?????? System.out.println(count);

??? }

}

六、并行流與串行流

并行流就是把一個內(nèi)容分成多個數(shù)據(jù)塊,并用不同的線程分別處理每個數(shù)據(jù)塊的流。

Java 8 中將并行進行了優(yōu)化,我們可以很容易的對數(shù)據(jù)進行并行操作。Stream API 可以聲明性地通過parallel() 與sequential() 在并行流與順序流之間進行切換。

Fork-Join框架的封裝實現(xiàn)。

七、Optional類

非重點了解。

Optional<T> 類(java.util.Optional) 是一個容器類,代表一個值存在或不存在,原來用null 表示一個值不存在,現(xiàn)在Optional 可以更好的表達這個概念。且可以避免空指針異常。

常用方法:

Optional.of(T t) : 創(chuàng)建一個Optional 實例

Optional.empty() : 創(chuàng)建一個空的Optional 實例

Optional.ofNullable(T t):若t 不為null,創(chuàng)建Optional 實例,否則創(chuàng)建空實例

isPresent() : 判斷是否包含值

orElse(T t) : 如果調(diào)用對象包含值,返回該值,否則返回t

orElseGet(Supplier s) :如果調(diào)用對象包含值,返回該值,否則返回s 獲取的值

map(Function f): 如果有值對其處理,并返回處理后的Optional,否則返回Optional.empty()

flatMap(Function mapper):與map 類似,要求返回值必須是Optional

import java.util.Optional;

import org.junit.Test;

/*

?*一、Optional 容器類:用于盡量避免空指針異常

?* Optional.of(Tt) :創(chuàng)建一個 Optional 實例

?* Optional.empty():創(chuàng)建一個空的 Optional 實例

?* Optional.ofNullable(Tt):若 t 不為 null,創(chuàng)建 Optional 實例,否則創(chuàng)建空實例

?* isPresent():判斷是否包含值

?* orElse(Tt) :? 如果調(diào)用對象包含值,返回該值,否則返回t

?* orElseGet(Suppliers) :如果調(diào)用對象包含值,返回該值,否則返回 s 獲取的值

?* map(Functionf):如果有值對其處理,并返回處理后的Optional,否則返回 Optional.empty()

?* flatMap(Functionmapper):與 map 類似,要求返回值必須是Optional

?*/

public classTestOptional {

??? @Test

??? public void test(){

?????? Optional?op = Optional.of(new Employee());

?????? Employee e = op.get();

?????? System.out.println(e);

??? }

}

八、接口中的默認方法與靜態(tài)方法

Java 8中允許接口中包含具有具體實現(xiàn)的方法,該方法稱為“默認方法”,默認方法使用default關(guān)鍵字修飾.

接口默認方法的”類優(yōu)先”原則

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

1:選擇父類中的方法。如果一個父類提供了具體的實現(xiàn),那么接口中具有相同名稱和參數(shù)的默認方法會被忽略。

2:接口沖突。如果一個父接口提供一個默認方法,而另一個接口也提供了一個具有相同名稱和參數(shù)列表的方法(不管方法是否是默認方法),那么必須覆蓋該方法來解決沖突

public interface?TestNewInterface {

??? default String getName(){

?????? return "this is testNewInterface";

??? }

??? public static void test(){

?????? System.out.println("thi is testNewInterface function : test");

??? }

}

public interface?TestNewInterface2 {

??? default String getName(){

?????? return "this is testNewInterface2";

??? }

??? public static void test(){

?????? System.out.println("thi is testNewInterface function : test2");

??? }

}

public classTestNewClass {

??? public String getName(){

?????? return "this is testNewClass";

??? }

}

??? public static void main(String[] args) {

?????? TestSubClass t = new TestSubClass();

?????? String str = t.getName();

?????? System.out.println(str);

?????? TestNewInterface.test();

??? }

}

運行結(jié)果:

this is testNewClass

thi is testNewInterface function : test

九、傳統(tǒng)時間格式化安全問題與新時間格式

新時間日期API

使用LocalDate、LocalTime、LocalDateTime、LocalTime、LocalDateTime 類的實例是不可變的對象,分別表示使用ISO-8601日歷系統(tǒng)的日期、時間、日期和時間。它們提供了簡單的日期或時間,并不包含當(dāng)前的時間信息。也不包含與時區(qū)相關(guān)的信息。

public classTestLocalDateTime {

??? @Test

??? public void test(){

?????? LocalDateTime ldt = LocalDateTime.now();

?????? System.out.println(ldt);

??? }

}

Instant 時間戳

?用于“時間戳”的運算。它是以Unix元年(傳統(tǒng)的設(shè)定為UTC時區(qū)1970年1月1日午夜時分)開始所經(jīng)歷的描述進行運算。

@Test

??? public void test1(){

?????? Instant inst = Instant.now();//默認獲取UTC時區(qū)

?????? System.out.println(inst);

?????? System.out.println(inst.toEpochMilli());//轉(zhuǎn)成毫秒時間戳

??? }

Duration:用于計算兩個“時間”間隔,計算兩個時間之間的間隔,示例:

@Test

??? public void test2(){

?????? Instant inst1 = Instant.now();

?????? Instant inst2 = Instant.now();

?????? Duration duration= Duration.between(inst1,inst2);

?????? System.out.println(duration.toMillis());


?????? LocalTime lt1 =LocalTime.now();

?????? LocalTime lt2 = LocalTime.now();

?????? Duration duration2 = Duration.between(lt1,lt2);

?????? System.out.println(duration2.toMillis());

??? }

Period:用于計算兩個“日期”間隔,示例:

@Test

??? public void test3(){

?????? LocalDate ld1 = LocalDate.of(2018, 9, 23);

?????? LocalDate ld2 = LocalDate.now();

?????? Period period = Period.between(ld1,ld2);

?????? System.out.println(period);

?????? System.out.println(period.getYears());

?????? System.out.println(period.getMonths());

?????? System.out.println(period.getDays());

??? }

TemporalAdjuster: 時間校正器。有時我們可能需要獲取例如:將日期調(diào)整到“下個周日”等操作。

TemporalAdjusters : 該類通過靜態(tài)方法提供了大量的常用TemporalAdjuster 的實現(xiàn)

自定義操作時間,時間校正器:

@Test

??? public void test4(){

?????? LocalDateTime ldt = LocalDateTime.now();

?????? LocalDateTime ldt5 = ldt.with((l) -> {

?????????? LocalDateTime ldt4 = (LocalDateTime)l;

?????????? DayOfWeek dow = ldt4.getDayOfWeek();

?????????? if(dow.equals(DayOfWeek.FRIDAY)){

????????????? return ldt4.plusDays(3);

?????????? }else{

????????????? return ldt4.plusDays(1);

?????????? }

?????? });

??? }

解析與格式化

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

1、預(yù)定義的標(biāo)準(zhǔn)格式。2、語言環(huán)境相關(guān)的格式。3、自定義的格式

@Test

??? public void test5(){

?????? //時間解析成字符串

?????? DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日");

?????? LocalDateTime ldt = LocalDateTime.now();

?????? String str = ldt.format(dtf);

?????? System.out.println(str);

?????? String str1 = dtf.format(ldt);

?????? System.out.println(str1);

?????? //字符串轉(zhuǎn)換成日期

?????? LocalDateTime ldt2 = LocalDateTime.parse(str,dtf);

?????? System.out.println(ldt2);

??? }

十、重復(fù)注解與類型注解

Java 8對注解處理提供了兩點改進:可重復(fù)的注解及可用于類型的注解,自行百度。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java 8自Java 5(發(fā)行于2004)以來最具革命性的版本。Java 8 為Java語言、編譯器、類庫、開發(fā)...
    huoyl0410閱讀 720評論 1 2
  • 目錄結(jié)構(gòu) 介紹 Java語言的新特性2.1 Lambdas表達式與Functional接口2.2 接口的默認與靜態(tài)...
    夜風(fēng)月圓閱讀 572評論 0 2
  • Nothing is imposible for a willing heart. Java 8 (又稱為 jdk...
    北緯26閱讀 1,089評論 1 6
  • 天龍八部第二部和第三部 你沒有成功,缺少按下一個確認鍵 列名單和種子法則 取經(jīng)不在于結(jié)果,而在于取經(jīng)的路上...
    大萍萍的幸福時光閱讀 672評論 0 0
  • 不愿想太多,安靜做項目,感情的事兒,不急。 有時單身,不是找不著,是沒遇到合適的合適的。 順其自然,繼續(xù)往前走,想...
    自寅日記閱讀 769評論 0 15

友情鏈接更多精彩內(nèi)容