JDK8 新特性學習筆記

java8新特性學習

java8的特點

  1. 速度更快(修改了HasMap、HasSet变勇、CurrentHasMap等存儲結(jié)構(gòu))
  2. 代碼更少(增加了新的語法Lambda表達式)
  3. 強大的Stream API
  4. 便于并行
  5. 最大化減少空指針異常

1.Lambda表達式

1.1对雪、Lambda表達式是什么缆巧?

Lambda是一個匿名函數(shù)司抱,我們可以把Lambda表達式理解為一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣傳遞)绪励∪乜玻可以寫出更簡潔澳眷、更靈活的代碼。作為一種更緊湊的代碼風格蛉艾,使Java的語言表達能力得到了提升钳踊。

1.2、Lambda表達式的基礎(chǔ)語法

Java8中引入了一個新的操作符“->”勿侯,該操作符稱為箭頭操作符或者Lambda操作符拓瞪,該操作符將Lambda表達式拆分成兩個部分:

左側(cè):Lambda表達式的參數(shù)列表。

右側(cè):Lambda表達式中需要執(zhí)行的功能助琐,即Lambda體祭埂。

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

() -> System.out.println("hello Lambda");

語法格式二:有一個參數(shù)弓柱,并且無返回值

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

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

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

語法格式四:有兩個以上的參數(shù),有返回值矢空,并且Lambda體中有多條語句

Comparator<Integer> com = (x,y) -> {
    System.out.println("函數(shù)式接口");
    return Integer.compare(x,y);
};

語法格式五:若Lambda體中只有一條語句航罗,return和大括號都可以省略不寫

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

語法格式六:Lambda表達式的參數(shù)列表的數(shù)據(jù)類型可以省略不寫,因為JVM編譯器通過上下文推斷出數(shù)據(jù)類型

(Integer x,Integer y) -> Integer.compare(x,y);

源代碼

package com.zgy.deom1;

import java.util.Comparator;
import java.util.function.Consumer;

import org.junit.jupiter.api.Test;

public class TestLambda2 {

    /*
     * Lambda基本語法:參數(shù)列表 -> 方法體
     */
    
    /*
     * 語法格式一:無參數(shù)屁药,無返回值
     *  () -> System.out.println("Hello World");
     */
    @Test
    public void test1() {
        int num = 0; //jdk8中當匿名內(nèi)部類中使用的變量粥血,會自動隱式添加final關(guān)鍵字,匿名內(nèi)部類中依然不能將變量進行加減操作酿箭。
        Runnable r = new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                System.out.println("hello world"+num);
            }
        };
        r.run();

        System.out.println("=============================");
        
        Runnable r1 = () -> System.out.println("hello lambda"+num);
        r1.run();
    }
    
    /*
     * 語法格式二:有一個參數(shù)复亏,沒有返回值
     */
    @Test
    public void test2() {
        Consumer<String> c = (x) -> System.out.println(x);
        c.accept(1+"");
        
        //Lambda表達式中如果參數(shù)只有一個,那么括號可以省略不寫
        Consumer<Object> c1 = x -> System.out.println("哈哈哈");
        c1.accept("ABC");
    }
    
    /*
     * 語法格式三:有兩個參數(shù)缭嫡,有返回值缔御,Lambda體中有多條語句
     */
    @Test
    public void test3() {
        Comparator<Integer> com = (x,y) -> {
            System.out.println("好好學習,天天向上妇蛀!");
            return x+y;
        };
        
        int result = com.compare(20, 30);
        System.out.println("result:"+result);
        
        //如果Lambda體中只有一條語句耕突,可以省略“{}”和return
        Comparator<Integer> c = (Integer x,Integer y) -> Integer.compare(x, y);
        int num = c.compare(30, 30);
        System.out.println("maxNub"+num);
        
        //由于JVM的類型推斷笤成,所以Lambda參數(shù)列表的數(shù)據(jù)類型,可以省略不寫
        Comparator<Integer> c1 = (x,y) -> Integer.compare(x, y);
        int num1 = c1.compare(30, 31);
        System.out.println("maxNub"+num1);
    }
    
    /*
     * 調(diào)用自定的函數(shù)式接口
     */
    @Test
    public void test4() {
        MyFun myFun = x -> x+100;
        int value = myFun.getValue(100);
        System.out.println("value:"+value);
    }
    
}
package com.zgy.deom1;

@FunctionalInterface
public interface MyFun {

    int getValue(int x);
}

練習代碼

package com.zgy.deom1;


import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.jupiter.api.Test;

public class TestLambda {

    
    List<Employee> emps = Arrays.asList(
            new Employee(101,"張三",18,9999.99),
            new Employee(102,"李四",59,6666.66),
            new Employee(103,"王五",28,3333.33),
            new Employee(104,"趙六",8,7777.77),
            new Employee(105,"田七",38,5555.55)
            );
    
    /*
     * 使用Collections對員工列表進行排序眷茁,按工資從多到少比
     * 關(guān)于Collections.sort()自定義排序規(guī)則炕泳,兩個參數(shù)x和y,如果要按照升序上祈,就是x在前面培遵;相反如果要按照降序,就是y在前面登刺。
     */
    @Test
    public void test1() {
        
        Collections.sort(emps, (x,y) -> Double.compare(y.getSalary(), x.getSalary()));
        for (Employee employee : emps) {
            System.out.println(employee);
        }
    }
    
    /*
     * 定義一個函數(shù)式接口籽腕,傳如一個參數(shù),返回該參數(shù)的大寫形式
     */
    @Test
    public void test2() {
        
        String str = strHandler("zgy", x -> x.toUpperCase());
        System.out.println("str:"+str);
    }
    
    //小寫轉(zhuǎn)大寫的方法
    public String strHandler(String str,MyFunction mf) {
        return mf.getValue(str);
    }
    
    /*
     * 聲明一個帶兩個泛型的函數(shù)式接口纸俭,泛型類型為<T,R> T為參數(shù)节仿,R為返回值,接口中聲明對應的抽象方法
     * 再使用接口作為參數(shù)掉蔬,計算兩個long型參數(shù)的和
     * 再計算兩個long型參數(shù)的積
     */
    @Test
    public void test3() {
        
        //計算和
        System.out.println(getValue(100L, 200L, (x,y) -> x+y));
        
        //計算積
        System.out.println(getValue(500L, 900L, (x,y) -> x*y));
    }
    
    public long getValue(Long x,Long y,MyFunction2<Long, Long> mf) {
        
        return mf.getValue(x, y);
    }
}
package com.zgy.deom1;

public class Employee {

    private int id;
    private String name;
    private int age;
    private double salary;
    
    public Employee() {}
    
    public Employee(int id, String name, int age, double salary) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
    
}
package com.zgy.deom1;

@FunctionalInterface
public interface MyFunction {

    public String getValue(String x);
}
package com.zgy.deom1;

@FunctionalInterface
public interface MyFunction2<T,R> {

    public R getValue(T t1, T t2);
}

1.3、函數(shù)式接口

函數(shù)式接口:接口中只有一個抽象方法的接口矾瘾,稱為函數(shù)式接口女轿,可以使用注解@FunctionalInterface修飾,該注解的作用是可以檢查該接口是否為函數(shù)式接口壕翩。

1.4蛉迹、Java8內(nèi)置四大核心函數(shù)式接口

image

Consumer<T>:消費型接口

? void accept(T t);

Supplier<T>:供給型接口

? T get();

Function<T, R>:函數(shù)型接口

? R apply(T t);

Predicate<T>:斷言型接口

? boolean test(T t);

其它子接口如下圖

image

源代碼

package com.zgy.deom1;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import org.junit.jupiter.api.Test;

/*
 * JDK8 內(nèi)置四大核心函數(shù)式接口
 */
public class TestLambda3 {

    /*
     * 消費式接口:傳一個參數(shù),沒有返回值
     * Consumer<T>  void accept(T t);
     */
    @Test
    public void test1() {
        say("好好學習放妈,天天向上北救!", x -> System.out.println(x+new Date()));
    }
    
    public void say(String str, Consumer<String> c) {
        c.accept(str);
    }
    
    /*
     * 供給式接口:沒有參數(shù),返回一個結(jié)果
     * Supplier<T>  T get();
     */
    @Test
    public void test2() {
        List<Integer> listResult = getNumberArr(() -> {
            List<Integer> list = new ArrayList<>();
            for(int i=0; i<10; i++) {               
                list.add(new Random().nextInt());
            }
            return list;
        });
        
        for (Integer integer : listResult) {
            System.out.println("DATA:"+integer);
        }
    }
    
    public List<Integer> getNumberArr(Supplier<List<Integer>> s){
        return s.get();
    } 
    
    /*
     * 函數(shù)式接口:傳入一個參數(shù)芜抒,返回一個結(jié)果
     * Function<T,R>  R apply(T t);
     */
    @Test
    public void test3() {
        System.out.println(apply("ZGY:", (x) -> x+new Date()));
    }
    
    public String apply(String a, Function<String, String> f) {
        return f.apply(a);
    };
    
    /*
     * 斷言型接口:傳入一個參數(shù)珍策,返回一個布爾值
     * Predicate<T>  boolean test(T t);
     */
    @Test
    public void test4() {
        System.out.println(test(40, x -> x>0));
    }
    
    public String test(int x, Predicate<Integer> p) {
        if(p.test(x)) {
            return "大于0";
        }else {
            return "小于0";
        }
    }
}

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

  1. 方法引用:若Lambda體中的內(nèi)容有方法已經(jīng)實現(xiàn)了宅倒,我們可以使用“方法引用”(可以理解為方法引用是Lambda表達式的另外一種表現(xiàn)形式)

    主要有三種語法格式:

    1. 對象 :: 實例方法名
    2. 類 :: 靜態(tài)方法名
    3. 類 :: 實例方法名

    注意:

    1. Lambda體中調(diào)用方法的參數(shù)列表與返回值類型攘宙,要與函數(shù)式接口中抽象方法的函數(shù)列表和返回值類型保持一致。
    2. 若Lambda參數(shù)列表中的第一個參數(shù)是實例方法的調(diào)用者拐迁,第二個參數(shù)是實例方法的參數(shù)蹭劈,可以用使用ClassName :: method
  2. 構(gòu)造器引用:

    格式:ClassName :: new

    注意:需要調(diào)用的構(gòu)造器參數(shù)列表要與函數(shù)式接口中抽象方法的參數(shù)列表保持一致

  3. 數(shù)組引用:

    格式:Type :: new;

源代碼

package com.zgy.deom1;

import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.junit.jupiter.api.Test;

public class TestMethodRef {

    /*
     * 方法引用和構(gòu)造器引用
     */
    
    @Test
    public void test1() {
        //對象 :: 實例方法名
        Consumer<String> c = System.out::println;
        c.accept("ZGY");
        
        Employee e = new Employee(111,"ZGY",22,1000);
        Supplier<String> s = e::getName;
        System.out.println(s.get());
    }
    
    @Test
    public void test2() {
        //類名::方法名
        Comparator<Integer> c = Integer::compare;
        System.out.println(c.compare(800, 210));
    }
    
    @Test
    public void test3() {
        //類名::實例方法名
        BiPredicate<String, String> bp = String::equals;
        System.out.println(bp.test("AAA", "AAA"));
    }
    
    @Test
    public void test4() {
        //構(gòu)造器引用
        Supplier<Employee> e = Employee::new;
        Employee employee = e.get();
        employee.setName("ZGY");
        System.out.println(employee);
    }
}

2、Stream API

2.1线召、什么是Stream

流(Stream)到底是什么铺韧?

流,是數(shù)據(jù)渠道缓淹,用于操作數(shù)據(jù)源(集合哈打、數(shù)組等)所生成的元素序列塔逃。集合講的是數(shù)據(jù),而流講的是計算前酿!

注意:

  1. Stream自己不會存儲元素患雏。
  2. Stream不會改變源對象,相反他們會返回一個持有結(jié)果的新Stream罢维。
  3. Stream是延遲執(zhí)行的淹仑,這意味著它們會等到需要結(jié)果的時候才會執(zhí)行。

2.2肺孵、Stream的操作三個步驟

image
  1. 創(chuàng)建Stream源碼

    package com.zgy.deom1;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Stream;
    
    import org.junit.jupiter.api.Test;
    
    /*
     * 創(chuàng)建Stream的幾種方式
     */
    public class TestStreamAPI1 {
    
     @Test
     public void test1() {
         //1.可以通過Collection系列集合提供的stream()或parallelStream()
         List<String> list = new ArrayList<>();
         Stream<String> stream = list.stream();
         
         //2.通過Arrays中的靜態(tài)方法stream()獲取數(shù)組流
         Employee[] employees = new Employee[10];
         Stream<Employee> stream2 = Arrays.stream(employees);
         
         //3.通過Stream類中的靜態(tài)方法of()
         Stream<String> stream3 = Stream.of("AA","BB","CC","DD");
         
         //4.通過迭代的方式創(chuàng)建無限流
         Stream<Integer> stream4 = Stream.iterate(0, x -> x+2);
         stream4.limit(5).forEach(System.out::println);
         
         //5.通過生成的方式創(chuàng)建無限流
         Stream<Double> stream5 = Stream.generate(() -> Math.random());
         //下面limit匀借、forEach分別是
         stream5.limit(20).forEach(System.out::println);
     }
    }
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市平窘,隨后出現(xiàn)的幾起案子吓肋,更是在濱河造成了極大的恐慌,老刑警劉巖瑰艘,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件是鬼,死亡現(xiàn)場離奇詭異,居然都是意外死亡紫新,警方通過查閱死者的電腦和手機均蜜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芒率,“玉大人囤耳,你說我怎么就攤上這事∨忌郑” “怎么了充择?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匪蟀。 經(jīng)常有香客問我椎麦,道長,這世上最難降的妖魔是什么材彪? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任铃剔,我火速辦了婚禮,結(jié)果婚禮上查刻,老公的妹妹穿的比我還像新娘键兜。我一直安慰自己,他們只是感情好穗泵,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布普气。 她就那樣靜靜地躺著,像睡著了一般佃延。 火紅的嫁衣襯著肌膚如雪现诀。 梳的紋絲不亂的頭發(fā)上夷磕,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音仔沿,去河邊找鬼坐桩。 笑死,一個胖子當著我的面吹牛封锉,可吹牛的內(nèi)容都是我干的绵跷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼成福,長吁一口氣:“原來是場噩夢啊……” “哼碾局!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起奴艾,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤净当,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蕴潦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體像啼,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年潭苞,在試婚紗的時候發(fā)現(xiàn)自己被綠了埋合。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡萄传,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜜猾,到底是詐尸還是另有隱情秀菱,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布蹭睡,位于F島的核電站衍菱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏肩豁。R本人自食惡果不足惜脊串,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一胁镐、第九天 我趴在偏房一處隱蔽的房頂上張望套像。 院中可真熱鬧弄痹,春花似錦萍诱、人聲如沸空郊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽教藻。三九已至篡悟,卻和暖如春谜叹,著一層夾襖步出監(jiān)牢的瞬間匾寝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工荷腊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留艳悔,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓女仰,卻偏偏與公主長得像猜年,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子董栽,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容