日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java定义苹果类Apple_Java开发笔记(七十)Java8新增的几种泛型接口

發(fā)布時(shí)間:2023/12/18 java 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java定义苹果类Apple_Java开发笔记(七十)Java8新增的几种泛型接口 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

由于泛型存在某種不確定的類型,因此很少直接運(yùn)用于拿來即用的泛型類,它更經(jīng)常以泛型接口的面目出現(xiàn)。例如幾種基本的容器類型Set、Map、List都被定義為接口interface,像HashSet、TreeMap、LinkedList等等只是實(shí)現(xiàn)了對(duì)應(yīng)容器接口的具體類罷了。泛型的用途各式各樣,近的不說,遠(yuǎn)的如數(shù)組工具Arrays的sort方法,它在排序時(shí)用到的比較器Comparator就是個(gè)泛型接口。別看Comparator.java的源碼洋洋灑灑數(shù)百行,其實(shí)它的精華部分僅僅下列寥寥數(shù)行:

//數(shù)組排序需要的比較器主要代碼,可見它是個(gè)泛型接口

public interface Comparator {

int compare(T o1, T o2);

}

當(dāng)然系統(tǒng)提供的泛型接口不止是Comparator一個(gè),從Java8開始,又新增了好幾個(gè)系統(tǒng)自帶的泛型接口,它們的適用范圍各有千秋,接下來便分別加以介紹。

1、斷言接口Predicate

之前介紹方法引用的時(shí)候,要求從一個(gè)字符串?dāng)?shù)組中挑選出符合條件的元素生成新數(shù)組,為此定義一個(gè)過濾器接口StringFilter,該接口聲明了字符串匹配方法isMatch,然后再利用該過濾器編寫字符串?dāng)?shù)組的篩選方法,進(jìn)而由外部通過Lambda表達(dá)式或者方法引用來進(jìn)行過濾。可是StringFilter這個(gè)過濾器只能用于篩選字符串,不能用來篩選其它數(shù)據(jù)類型。若想讓它支持所有類型的數(shù)據(jù)篩選,勢(shì)必要把數(shù)據(jù)類型空泛化,Java8推出的斷言接口Predicate正是這種用于匹配校驗(yàn)的泛型接口。

在詳細(xì)說明Predicate之前,先定義一個(gè)蘋果類Apple,本文的幾個(gè)泛型接口都準(zhǔn)備拿蘋果類練手,它的類定義代碼如下所示:

//定義一個(gè)蘋果類

public class Apple {

private String name; // 名稱

private String color; // 顏色

private Double weight; // 重量

private Double price; // 價(jià)格

public Apple(String name, String color, Double weight, Double price) {

this.name = name;

this.color = color;

this.weight = weight;

this.price = price;

}

// 為節(jié)省篇幅,此處省略每個(gè)成員屬性的get/set方法

// 獲取該蘋果的詳細(xì)描述文字

public String toString() {

return String.format("\n(name=%s,color=%s,weight=%f,price=%f)", name,

color, weight, price);

}

// 判斷是否紅蘋果

public boolean isRedApple() {

return this.color.toLowerCase().equals("red");

}

}

接著構(gòu)建一個(gè)填入若干蘋果信息的初始清單,幾種泛型接口準(zhǔn)備對(duì)蘋果清單磨刀霍霍,清單數(shù)據(jù)的構(gòu)建代碼示例如下:

// 獲取默認(rèn)的蘋果清單

private static List getAppleList() {

// 數(shù)組工具Arrays的asList方法可以把一系列元素直接賦值給清單對(duì)象

List appleList = Arrays.asList(

new Apple("紅蘋果", "RED", 150d, 10d),

new Apple("大蘋果", "green", 250d, 10d),

new Apple("紅蘋果", "red", 300d, 10d),

new Apple("大蘋果", "yellow", 200d, 10d),

new Apple("紅蘋果", "green", 100d, 10d),

new Apple("大蘋果", "Red", 250d, 10d));

return appleList;

}

然后當(dāng)前的主角——斷言接口終于登場(chǎng)了,別看“斷言”二字似乎很嚇人,其實(shí)它的關(guān)鍵代碼也只有以下幾行,真正有用的就是校驗(yàn)方法test:

public interface Predicate {

boolean test(T t);

}

再定義一個(gè)清單過濾的泛型方法,輸入原始清單和斷言實(shí)例,輸出篩選后符合條件的新清單。過濾方法的處理邏輯很簡單,僅僅要求遍歷清單的所有元素,一旦通過斷言實(shí)例的test方法檢驗(yàn),就把該元素添加到新的清單。具體的過濾代碼如下所示:

// 利用系統(tǒng)自帶的斷言接口Predicate,對(duì)某個(gè)清單里的元素進(jìn)行過濾

private static List filterByPredicate(List list, Predicate p) {

List result = new ArrayList();

for (T t : list) {

if (p.test(t)) { // 如果滿足斷言的測(cè)試條件,則把該元素添加到新的清單

result.add(t);

}

}

return result;

}

終于輪到外部調(diào)用剛才的過濾方法了,現(xiàn)在要求從原始的蘋果清單中挑出所有的紅蘋果,為了更直觀地理解泛型接口的運(yùn)用,先通過匿名內(nèi)部類方式來表達(dá)Predicate實(shí)例。此時(shí)的調(diào)用代碼是下面這樣的:

// 測(cè)試系統(tǒng)自帶的斷言接口Predicate

private static void testPredicate() {

List appleList = getAppleList();

// 第一種調(diào)用方式:匿名內(nèi)部類實(shí)現(xiàn)Predicate。挑出所有的紅蘋果

List redAppleList = filterByPredicate(appleList, new Predicate() {

@Override

public boolean test(Apple t) {

return t.isRedApple();

}

});

System.out.println("紅蘋果清單:" + redAppleList.toString());

}

運(yùn)行上述的測(cè)試代碼,從輸出的日志信息可知,通過斷言接口正確篩選到了紅蘋果清單:

紅蘋果清單:[

(name=紅蘋果,color=RED,weight=150.000000,price=10.000000),

(name=紅蘋果,color=red,weight=300.000000,price=10.000000),

(name=大蘋果,color=Red,weight=250.000000,price=10.000000)]

顯然匿名內(nèi)部類的實(shí)現(xiàn)代碼過于冗長,改寫為Lambda表達(dá)式的話僅有以下一行代碼:

// 第二種調(diào)用方式:Lambda表達(dá)式實(shí)現(xiàn)Predicate

List redAppleList = filterByPredicate(appleList, t -> t.isRedApple());

或者采取方法引用的形式,也只需下列的一行代碼:

// 第三種調(diào)用方式:通過方法引用實(shí)現(xiàn)Predicate

List redAppleList = filterByPredicate(appleList, Apple::isRedApple);

除了挑選紅蘋果,還可以挑選大個(gè)的蘋果,比如要挑出所有重量大于半斤的蘋果,則采取Lambda表達(dá)式的的調(diào)用代碼見下:

// Lambda表達(dá)式實(shí)現(xiàn)Predicate。挑出所有重量大于半斤的蘋果

List heavyAppleList = filterByPredicate(appleList, t -> t.getWeight() >= 250);

System.out.println("重蘋果清單:" + heavyAppleList.toString());

以上的代碼演示結(jié)果,充分說明了斷言接口完全適用于過濾判斷及篩選操作。

2、消費(fèi)接口Consumer

斷言接口只進(jìn)行邏輯判斷,不涉及到數(shù)據(jù)修改,若要修改清單里的元素,就用到了另一個(gè)消費(fèi)接口Consumer。譬如下館子消費(fèi),把肚子撐大了;又如去超市消費(fèi),手上多了裝滿商品的購物袋;因此消費(fèi)行為理應(yīng)伴隨著某些屬性的變更,變大或變小,變多或變少。Consumer同樣屬于泛型接口,它的核心代碼也只有以下區(qū)區(qū)幾行:

public interface Consumer {

void accept(T t);

}

接著將消費(fèi)接口作用于清單對(duì)象,意圖修改清單元素的某些屬性,那么得定義泛型方法modifyByConsumer,根據(jù)輸入的清單數(shù)據(jù)和消費(fèi)實(shí)例,從而對(duì)清單執(zhí)行指定的消費(fèi)行為。詳細(xì)的修改方法示例如下:

// 利用系統(tǒng)自帶的消費(fèi)接口Consumer,對(duì)某個(gè)清單里的元素進(jìn)行修改

private static void modifyByConsumer(List list, Consumer c) {

for (T t : list) {

// 根據(jù)輸入的消費(fèi)指令接受變更,所謂消費(fèi),通俗地說,就是女人花錢打扮自己。

// 下面的t既是輸入?yún)?shù),又允許修改。

c.accept(t); // 如果t是String類型,那么accept方法不能真正修改字符串

}

}

消費(fèi)行為仍然拿蘋果清單小試牛刀,外部調(diào)用modifyByConsumer方法之時(shí),傳入的消費(fèi)實(shí)例要給蘋果名稱加上“好吃”二字。下面便是具體的調(diào)用代碼例子,其中一塊列出了匿名內(nèi)部類與Lambda表達(dá)式這兩種寫法:

// 測(cè)試系統(tǒng)自帶的消費(fèi)接口Consumer

private static void testConsumer() {

List appleList = getAppleList();

// 第一種調(diào)用方式:匿名內(nèi)部類實(shí)現(xiàn)Consumer。在蘋果名稱后面加上“好吃”二字

modifyByConsumer(appleList, new Consumer() {

@Override

public void accept(Apple t) {

t.setName(t.getName() + "好吃");

}

});

// 第二種調(diào)用方式:Lambda表達(dá)式實(shí)現(xiàn)Consumer

modifyByConsumer(appleList, t -> t.setName(t.getName() + "好吃"));

System.out.println("好吃的蘋果清單" + appleList.toString());

}

運(yùn)行上面的調(diào)用代碼,可見輸入的日志記錄果然給蘋果名稱補(bǔ)充了兩遍“好吃”:

好吃的蘋果清單[

(name=紅蘋果好吃好吃,color=RED,weight=150.000000,price=10.000000),

(name=大蘋果好吃好吃,color=green,weight=250.000000,price=10.000000),

(name=紅蘋果好吃好吃,color=red,weight=300.000000,price=10.000000),

(name=大蘋果好吃好吃,color=yellow,weight=200.000000,price=10.000000),

(name=紅蘋果好吃好吃,color=green,weight=100.000000,price=10.000000),

(name=大蘋果好吃好吃,color=Red,weight=250.000000,price=10.000000)]

不過單獨(dú)使用消費(fèi)接口的話,只能把清單里的每個(gè)元素全部修改過去,不加甄別的做法顯然太粗暴了。更好的辦法是挑出符合條件的元素再做變更,如此一來就得聯(lián)合運(yùn)用斷言接口與消費(fèi)接口,先通過斷言接口Predicate篩選目標(biāo)元素,再通過消費(fèi)接口Consumer處理目標(biāo)元素。于是結(jié)合兩種泛型接口的泛型方法就變成了以下這般代碼:

// 聯(lián)合運(yùn)用Predicate和Consumer,可篩選出某些元素并給它們整容

private static void selectAndModify(List list, Predicate p, Consumer c) {

for (T t : list) {

if (p.test(t)) { // 如果滿足斷言的條件要求,

c.accept(t); // 就把該元素送去美容院整容。

}

}

}

針對(duì)特定的記錄再作調(diào)整,正是實(shí)際業(yè)務(wù)場(chǎng)景中的常見做法。比如現(xiàn)有一堆蘋果,因?yàn)槊總€(gè)蘋果的質(zhì)量參差不齊,所以要對(duì)蘋果分類定價(jià)。一般的蘋果每公斤賣10塊錢,如果是紅彤彤的蘋果,則單價(jià)提高50%;如果蘋果個(gè)頭很大(重量大于半斤),則單價(jià)也提高50%;又紅又大的蘋果想都不要想肯定特別吃香,算下來它的單價(jià)足足是一般蘋果的1.5*1.5=2.25倍了。那么調(diào)整蘋果定價(jià)的代碼邏輯就得先后調(diào)用兩次selectAndModify方法,第一次用來調(diào)整紅蘋果的價(jià)格,第二次用來調(diào)整大蘋果的價(jià)格,完整的價(jià)格調(diào)整代碼如下所示:

// 聯(lián)合測(cè)試斷言接口Predicate和消費(fèi)接口Consumer

private static void testPredicateAndConsumer() {

List appleList = getAppleList();

// 如果是紅蘋果,就漲價(jià)五成

selectAndModify(appleList, t -> t.isRedApple(), t -> t.setPrice(t.getPrice() * 1.5));

// 如果重量大于半斤,再漲價(jià)五成

selectAndModify(appleList, t -> t.getWeight() >= 250, t -> t.setPrice(t.getPrice() * 1.5));

System.out.println("漲價(jià)后的蘋果清單:" + appleList.toString());

}

運(yùn)行以上的價(jià)格調(diào)整代碼,從以下輸出的日志結(jié)果可知,每個(gè)蘋果的單價(jià)都經(jīng)過計(jì)算重新改過了:

漲價(jià)后的蘋果清單:[

(name=紅蘋果,color=RED,weight=150.000000,price=15.000000),

(name=大蘋果,color=green,weight=250.000000,price=15.000000),

(name=紅蘋果,color=red,weight=300.000000,price=22.500000),

(name=大蘋果,color=yellow,weight=200.000000,price=10.000000),

(name=紅蘋果,color=green,weight=100.000000,price=10.000000),

(name=大蘋果,color=Red,weight=250.000000,price=22.500000)]

3、函數(shù)接口Function

剛才聯(lián)合斷言接口和消費(fèi)接口,順利實(shí)現(xiàn)了修改部分元素的功能,然而這種做法存在問題,就是直接在原清單上面進(jìn)行修改,一方面破壞了原始數(shù)據(jù),另一方面仍未抽取到新清單。于是Java又設(shè)計(jì)了泛型的函數(shù)接口Function,且看它的泛型接口定義代碼:

public interface Function {

R apply(T t);

}

從Function的定義代碼可知,該接口不但支持輸入某個(gè)泛型變量,也支持返回另一個(gè)泛型變量。這樣的話,把輸入?yún)?shù)同輸出參數(shù)區(qū)分開,就避免了二者的數(shù)據(jù)處理操作發(fā)生干擾。據(jù)此可編寫新的泛型方法recycleByFunction,該方法輸入原始清單和函數(shù)實(shí)例,輸出處理后的新清單,從而滿足了數(shù)據(jù)抽取的功能需求。詳細(xì)的方法代碼示例如下:

// 利用系統(tǒng)自帶的函數(shù)接口Function,把所有元素進(jìn)行處理后加到新的清單里面

private static List recycleByFunction(List list, Function f) {

List result = new ArrayList();

for (T t : list) {

R r = f.apply(t); // 把原始材料t加工一番后輸出成品r

result.add(r); // 把成品r添加到新的清單

}

return result;

}

接下來由外部去調(diào)用新定義的recycleByFunction方法,照舊采取匿名內(nèi)部類與Lambda表達(dá)式同時(shí)進(jìn)行編碼,輪番對(duì)紅蘋果和大蘋果漲價(jià),修改后的調(diào)用代碼例子見下:

// 測(cè)試系統(tǒng)自帶的函數(shù)接口Function

private static void testFunction() {

List appleList = getAppleList();

List appleRecentList;

// 第一種調(diào)用方式:匿名內(nèi)部類實(shí)現(xiàn)Function。把漲價(jià)后的蘋果放到新的清單之中

appleRecentList = recycleByFunction(appleList,

new Function() {

@Override

public Apple apply(Apple t) {

Apple apple = new Apple(t.getName(), t.getColor(), t.getWeight(), t.getPrice());

if (apple.isRedApple()) { // 如果是紅蘋果,就漲價(jià)五成

apple.setPrice(apple.getPrice() * 1.5);

}

if (apple.getWeight() >= 250) { // 如果重量大于半斤,再漲價(jià)五成

apple.setPrice(apple.getPrice() * 1.5);

}

return apple;

}

});

// 第二種調(diào)用方式:Lambda表達(dá)式實(shí)現(xiàn)Function

appleRecentList = recycleByFunction(appleList, t -> {

Apple apple = new Apple(t.getName(), t.getColor(), t.getWeight(), t.getPrice());

if (apple.isRedApple()) { // 如果是紅蘋果,就漲價(jià)五成

apple.setPrice(apple.getPrice() * 1.5);

}

if (apple.getWeight() >= 250) { // 如果重量大于半斤,再漲價(jià)五成

apple.setPrice(apple.getPrice() * 1.5);

}

return apple;

});

System.out.println("漲價(jià)后的新蘋果清單:" + appleRecentList.toString());

}

注意到上面的例子代碼中,函數(shù)接口的入?yún)㈩愋蜑锳pple,而出參類型也為Apple。假設(shè)出參類型不是Apple,而是別的類型如String,那該當(dāng)若何?其實(shí)很簡單,只要函數(shù)接口的返回參數(shù)改成其它類型就好了。譬如現(xiàn)在無需返回蘋果的完整清單,只需返回蘋果的名稱清單,則調(diào)用代碼可調(diào)整為下面這樣:

// 返回的清單類型可能與原清單類型不同,比如只返回蘋果名稱

List colorList = recycleByFunction(appleList,

t -> t.getName() + "(" + t.getColor() + ")");

System.out.println("帶顏色的蘋果名稱清單:" + colorList.toString());

運(yùn)行以上的調(diào)整代碼,果然打印了如下的蘋果名稱清單日志:

帶顏色的蘋果名稱清單:[紅蘋果(RED), 大蘋果(green), 紅蘋果(red), 大蘋果(yellow), 紅蘋果(green), 大蘋果(Red)]

總結(jié)

以上是生活随笔為你收集整理的java定义苹果类Apple_Java开发笔记(七十)Java8新增的几种泛型接口的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。