day15 泛型、異常芒澜、lambda表達式

泛型仰剿、異常、lambda表達式

泛型

可以在類和方法中預支地使用未知的類型痴晦,一般在創(chuàng)建對象時南吮,將位置類型確定為具體類型,當沒有指定泛型時候誊酌, 默認類型是Obj類型部凑。

使用泛型的好處

  • 將運行時時期的異常露乏,轉移到了編譯時期變成了編譯失敗
  • 避免了類型強轉的麻煩
public class GenericDemo {
    public static void main(String[] args) {
        Collection<String> list = new ArrayList<>();
        list.add("abc");
        list.add("def");
        // list.add(5); 集合已經(jīng)明確了具體元素存放的類型
        // 已經(jīng)明確了類型,在使用迭代器的時候涂邀,迭代器也同樣知道遍歷元素的具體類型
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String str = iterator.next();
            // 使用iterator()在這里可以直接獲取String類型
            System.out.println(str.length());
        }
        
        System.out.println(list);

    }
}

泛型的定義與使用

泛型瘟仿,用來靈活的將數(shù)據(jù)類型應用到不同類、方法比勉、接口當中劳较。將數(shù)據(jù)類型作為參數(shù)進行傳遞。
格式

修飾符  class 類名<代表泛型的變量>{
}

使用泛型:在創(chuàng)建對象的時候確定泛型
自定義泛型

public class MyGenericClass<MVP> {
    // 沒有MVP類型敷搪, 在這里代表未知的一種數(shù)據(jù)類型
    // 未來傳遞什么就是什么類型
    private MVP mvp;

    public MVP getMvp() {
        return mvp;
    }

    public void setMvp(MVP mvp) {
        this.mvp = mvp;
    }
}

測試

public class TestGenericDemo {
    public static void main(String[] args) {
        // 創(chuàng)建一個泛型為String類
        MyGenericClass<String> my = new MyGenericClass<>();
        my.setMvp("哈登哥");
        String mvp = my.getMvp();
        System.out.println(mvp);

        MyGenericClass<Integer> my2 = new MyGenericClass<>();
        my2.setMvp(13);
        Integer mvp2 = my2.getMvp();
        System.out.println(mvp2);


    }
}

含有泛型的方法

格式:

修飾符 <代表泛型的變量> 返回值類型 方法名(參數(shù)列表){
}

舉個栗子

public class MyGenericMethod {
    public <MVP>void show(MVP mvp){
        System.out.println(mvp.getClass());
    }
    public <MVP>  MVP show2(MVP mvp){
        return mvp;
    }
}

測試

public class TestGenericDemo2 {
    public static void main(String[] args) {
        MyGenericMethod mgm = new MyGenericMethod();
        // 在調(diào)用方法時兴想, 確定泛型的類型
        mgm.show("aaa");
        mgm.show(123);
        mgm.show(12.45);

    }
}

含有泛型的接口

格式

修飾符  interface 接口名<泛型>{
}

舉個栗子

public interface MyGenericInterface<E> {
    public abstract void add(E e);
    public abstract E getE();
    
}

實現(xiàn)類在定義類的時候確定泛型的類型

public class MyGenericImpl implements MyGenericInterface<String> {

    @Override
    public void add(String s) {

    }

    @Override
    public String getE() {
        return null;
    }
}

上面泛型 E 的值就是String類型

始終不確定泛型的類型幢哨,直到創(chuàng)建對象的時候赡勘,確定泛型的類型

public class MyGenericImpl2<E> implements MyGenericInterface<E> {
    @Override
    public void add(E e) {

    }

    @Override
    public E getE() {
        return null;
    }
}

確定泛型

public class TestGenericDemo2 {
    public static void main(String[] args) {
        MyGenericImpl2<String> impl2 = new MyGenericImpl2<>();
        ArrayList<Object> list = new ArrayList<>();
        impl2.add("hehe");

    }
}

泛型通配符

常用的通配符含義

  • E Element(在集合中使用)
  • T Type(Java類)
  • K Key(鍵)
  • V Value (值)
  • N Number(數(shù)值類型)
  • ? 表示不確定的Java類型
    <捞镰?> 表示不確定的Java類型闸与, 一旦使用<?> 只能使用Object類中的共性方法
基本使用

<岸售?> 不知道到使用什么類型來接受的時候

public class TestGenericDemo3 {
    public static void main(String[] args) {
        Collection<Integer> list1 = new ArrayList<>();
        Collection<String> list2 = new ArrayList<>();
        getElement(list1);
        getElement(list2);
    }
    public static void getElement(Collection<?> coll){
        // <?>代表可以接受任意類型
    }
}

高級應用--- 受限類型

在Java中的泛型可以指定一個泛型的上限和下限

泛型的上限:

格式  : 類型名稱<践樱? extends 類 > 對象名稱
意義 : 只能接受該類型及其子類

泛型的下限:

格式  : 類型名稱<? super 類 > 對象名稱
意義 : 只能接受該類型及其父類

舉個栗子:現(xiàn)在已知Object類凸丸、String類拷邢、Number類、Integer類屎慢,其中Number類是Integer類的父類

public class TestGenericDemo4 {
    public static void main(String[] args) {
        Collection<Integer> list1 = new ArrayList<>();
        Collection<String> list2 = new ArrayList<>();
        Collection<Number> list3 = new ArrayList<>();
        Collection<Object> list4 = new ArrayList<>();
        getElement1(list1);
        getElement1(list2);// 報錯
        getElement1(list3);
        getElement1(list4); // 報錯
        
        getElement2(list1)// 報錯
        getElement2(list2)// 報錯
        getElement2(list3)// 報錯
        getElement2(list4)// 報錯
    }
    // 泛型的上限 此時泛型瞭稼?必須是Number類型或者Number類型子類
    public static void getElement1(Collection<? extends Number> coll){
    }
    // 泛型的下限 此時泛型?必須是Number類型或者Number類型父類
    public static void getElement2(Collection<? super Number> coll){
    }
}

異常

異常: 指的是程序在執(zhí)行過程中腻惠,出現(xiàn)的非正常的情況环肘,最終會導致JVM的非正常停止
在Java中異常本身是一個類, 產(chǎn)生異常就是創(chuàng)建異常對象并且拋出了一個異常對象集灌。Java處理異常的方式是中斷處理

異常不是語法錯誤悔雹, 語法錯誤是無法通過編譯

異常體系

異常的根類是 java.lang.Throwable,兩個子類 java.lang.Error和 java.lang.Exception
平時所說的異常是java.lang.Exception
Throwable體系:

  • Error: 嚴重錯誤欣喧,無法通過處理的錯誤腌零,好比絕癥
  • Exception表示異常, 異常產(chǎn)生后程序員可以通過代碼的方式糾正唆阿,使程序繼續(xù)運行益涧,是必須處理的。好比感冒發(fā)燒
常用方法
  • public void printStackTrace()酷鸦; 打印異常的詳細信息并且輸出到控制臺中
  • public String getMessage(); 獲取發(fā)生異常的原因

舉個栗子

public class Demo1 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 4};
        System.out.println(arr[3]);
    }
}
image

異常的分類

  • 編譯時期異常: 如果沒有處理饰躲,編譯失斞烙健(如日期格式化異常)
  • 運行時期異常: 在運行時期檢查異常 (如數(shù)學異常)


    image

異常處理

Java中異常處理的五個關鍵字:try、catch嘹裂、finally妄壶、throw、throws

拋出異常throw

  • 創(chuàng)建一個異常對象寄狼。封裝一些提示信息(信息可以自己編寫)
  • 通過throw將這個異常對象告知調(diào)用者丁寄,throw用在方法內(nèi),用來拋出一個異常對象泊愧,將這個異常對象傳遞到調(diào)用者處伊磺,并結束當前方法的執(zhí)行。
  • 格式
throw new 異常類名(參數(shù))删咱;

舉個栗子

throw new NullPointerException("要訪問的arr數(shù)組不存在");
throw new ArrayIndexOutOfBoundsException("數(shù)組越界了屑埋,兄弟");
public class Demo2 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 4, 5};
        int index = 4;
        int element = getElement(arr, index);
        System.out.println(element);
    }
    public static int getElement(int[] arr, int index){
        // 判斷
        if (index < 0 || index> arr.length-1){
            throw new ArrayIndexOutOfBoundsException("數(shù)組越界了,兄弟");
        }
       return arr[index];
    }
}

聲明異常throws

聲明異常:將為題標識出來痰滋, 報告給調(diào)用者摘能, 如果方法內(nèi)通過throw 拋出了編譯時異常, 而沒有捕獲處理敲街,那么必須通過throws進行聲明团搞,讓調(diào)用者去處理

修飾符 <代表泛型的變量> 返回值類型 方法名(參數(shù)列表) throws 異常類1, 異常類2 {
}

舉個栗子

public class Demo3 {
    public static void main(String[] args) throws ParseException {
        String s = "1994-12";
        timeFormat(s);

    }
    public static void timeFormat(String str) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Date date = sdf.parse(str);
        System.out.println(date);
    }
}

捕獲異常try catch

如果異常出現(xiàn)會立刻終止程序多艇, 所以我們得處理異常

  1. 聲明拋出, 由調(diào)用者來處理(throws)
  2. 使用try catch語句塊來處理異常
    try catch的方式就是捕獲異常
    格式:
try {
    編寫可能會出現(xiàn)異常的地方
}catch(異常類型 e){
    // 處理異常的代碼
    // 記錄日志逻恐、打印異常信息、繼續(xù)拋出異常
}
  • try 編寫可能會出現(xiàn)異常的代碼
  • catch 異常的捕獲進行處理
  • try catch不能單獨使用峻黍, 必須連用
public class Demo4 {
    public static void main(String[] args) {
        try {
            read("xiaomiMi.txt");
        } catch (Exception e) {
            // 在try中拋出什么異常复隆,在括號中就捕獲什么異常類型
//            e.printStackTrace();
            System.out.println("++++++++");
            System.out.println(e);
        }
        System.out.println("end");
    }
    public static void read(String path) throws FileNotFoundException {
        if (!path.equals("xiaomimi.txt")){
            throw new FileNotFoundException("你的文件怎么消失了呢");
        }
    }
}

finally 代碼塊

finally: 有一些特定的代碼,無論是否發(fā)生異常都要執(zhí)行奸披,另外昏名,因為異常會引發(fā)程序跳轉,導致有些語句執(zhí)行不到阵面, 而finally就解決了這個問題轻局。

  • finally不能單獨使用
public class Demo4 {
    public static void main(String[] args) {
        try {
            read("xiaomiMi.txt");
        } catch (Exception e) {
            // 在try中拋出什么異常,在括號中就捕獲什么異常類型
//            e.printStackTrace();
            System.out.println("++++++++");
            System.out.println(e);
        }finally {
            System.out.println("不管try和catch執(zhí)行啥了样刷,我這里都會執(zhí)行");
            System.out.println("我是接盤俠");
        }
        System.out.println("end");
    }
    public static void read(String path) throws FileNotFoundException {
        if (!path.equals("xiaomimi.txt")){
            throw new FileNotFoundException("你的文件怎么消失了呢");
        }
    }
}

l# ambda表達式
是JDK1.8版本的新特性仑扑, lambda 省去面向對象的條條框框,格式由3部分組成

  • 一些參數(shù)
  • 一個箭頭
  • 一段代碼
    標準格式:
(參數(shù)類型  參數(shù)名) -> { 代碼語句 }

說明

  • 小括號就是傳統(tǒng)的參數(shù)列表置鼻,多個用逗號分隔
  • -> 代表指向動作
  • 大括號和原來一樣寫方法體
無參無返回
public interface Cook {
    void makeFood();
}
public class Demo2 {
    public static void main(String[] args) {
        invoke(()->{
            System.out.println("lambda表達式做的飯好了");
        });
    }
    public static void invoke(Cook cook){
        cook.makeFood();
    }
}

小括號代表Cook接口的makeFood方法參數(shù)為空镇饮, 大括號代表makeFood的方法體

有參有返回值

需求:使用數(shù)組存儲多個Person對象,對數(shù)組中的Person對象使用Arrays的sort方法通過年齡排序箕母;
代碼分析

  • 為了排序储藐, Arrays.sort需要排序規(guī)則俱济, Comparator接口的實例,實現(xiàn)compare方法
  • 為了實現(xiàn)compare方法钙勃,不得不寫一個Comparator的實現(xiàn)類
  • 為了省略Comparator的實現(xiàn)類ComparatorImpl蛛碌,不得不使用匿名內(nèi)部類
  • 必須覆蓋compare方法,所有的聲明都需要重寫一遍
  • 實際上辖源, 只有參數(shù)和方法體是關鍵部分

Lambda寫法

public class Demo4 {
    public static void main(String[] args) {
        Person[] array = {
                new Person("貂蟬", 223),
                new Person("孫尚香", 18),
                new Person("妲己", 300),
                new Person("楊玉環(huán)", 221),
        };
        Arrays.sort(array, (Person a, Person b)->{
            return a.getAge()-b.getAge();
        });
        for (Person person :array){
            System.out.println(person);
        }
    } 
}
需求:給定一個計算器Calculator接口蔚携,內(nèi)含抽象方法calc可以將連個int類型的數(shù)組相加得到和的值
public interface Calculator {
    int calc(int a , int b);
}
public class Demo5 {
    public static void main(String[] args) {
        // 使用lambda表達式 調(diào)用測試
        invokeCalc(5,6, (int a, int b)->{
            return a + b;
        });
                
    }
    public static void invokeCalc(int a, int b, Calculator calculator){
        int res = calculator.calc(a, b);
        System.out.println("res = "+ res);
    }
}
省略格式:

Lambda強調(diào)做什么, 而不是怎么做克饶, 凡是可以根據(jù)上下文推導得知的消息酝蜒,都可以省略

public class Demo6 {
    public static void main(String[] args) {
        // 使用lambda表達式 調(diào)用測試
        invokeCalc(5,6, (a, b)-> a + b);
    }
    public static void invokeCalc(int a, int b, Calculator calculator){
        int res = calculator.calc(a, b);
        System.out.println("res = "+ res);
    }
}

省略規(guī)則:

  • 小括號內(nèi)參數(shù)可以省略
  • 如果小括號內(nèi)有且僅有一個參, 小括號可以省略
  • 如果大括號內(nèi)有有且僅有一個語句矾湃,則無論是否有返回值亡脑,都可以省略大括號、return及語句分號
public class Demo7 {
    public static void main(String[] args) {
        // 使用lambda表達式 調(diào)用測試
        invokeShow(100, a -> a + 100);
    }
    public static void invokeShow(int a, Show show){
       int res = show.showNum(a);
        System.out.println(res);

    }
}

改寫之前廚子

public class Demo8 {
    public static void main(String[] args) {
       invoke(()-> System.out.println("省略在做飯"));

    }
    public static void invoke(Cook cook){
        cook.makeFood();
    }
}

Lambda使用前提

  1. 使用Lambda必須具有接口洲尊,且要求接口中有且僅有一個抽象方法(無論是Runable远豺、Comparator接口還是自己定義的接口奈偏,都得是抽象方法唯一)
  2. 使用Lambda必須具有上下文推斷.坞嘀;也就是方法的參數(shù)或者局部變量類型必須為Lambda對應的接口類型,才能使用Lambda作為該接口的實例
    有且只有一個抽象方法的接口叫做函數(shù)式接口
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惊来,一起剝皮案震驚了整個濱河市丽涩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌裁蚁,老刑警劉巖矢渊,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異枉证,居然都是意外死亡矮男,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門室谚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來毡鉴,“玉大人,你說我怎么就攤上這事秒赤≈硭玻” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵入篮,是天一觀的道長陈瘦。 經(jīng)常有香客問我,道長潮售,這世上最難降的妖魔是什么痊项? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任锅风,我火速辦了婚禮,結果婚禮上鞍泉,老公的妹妹穿的比我還像新娘遏弱。我一直安慰自己,他們只是感情好塞弊,可當我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布漱逸。 她就那樣靜靜地躺著,像睡著了一般游沿。 火紅的嫁衣襯著肌膚如雪饰抒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天诀黍,我揣著相機與錄音袋坑,去河邊找鬼。 笑死眯勾,一個胖子當著我的面吹牛枣宫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播吃环,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼也颤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了郁轻?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤好唯,失蹤者是張志新(化名)和其女友劉穎竭沫,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜕提,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姐霍。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖镊折,靈堂內(nèi)的尸體忽然破棺而出恨胚,到底是詐尸還是另有隱情骂因,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布赃泡,位于F島的核電站寒波,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏升熊。R本人自食惡果不足惜俄烁,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望级野。 院中可真熱鬧页屠,春花似錦、人聲如沸蓖柔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽况鸣。三九已至牢贸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間懒闷,已是汗流浹背十减。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留愤估,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓速址,卻偏偏與公主長得像玩焰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子芍锚,可洞房花燭夜當晚...
    茶點故事閱讀 43,494評論 2 348