国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
一、Stream中間操作
1.1、filter:過濾出符合條件的元素
1.2、map:映射轉(zhuǎn)換元素
1.3、flatMap:將多個(gè)流合併為一個(gè)流
1.4、distinct:去除重複的元素
1.5、sorted:排序元素
1.7、limit 和 skip:截取流中的部分元素
二、Stream終止操作
2.1、forEach:遍歷流中的每個(gè)元素
2.2、count:統(tǒng)計(jì)流中元素的數(shù)量
2.3、reduce:將流中的所有元素歸約成一個(gè)結(jié)果
2.4、collect:將流中的元素收集到一個(gè)容器中,并返回該容器
2.5、min 和 max:找出流中的最小值和最大值
2.6、anyMatch、allMatch 和 noneMatch:判斷流中是否存在滿足指定條件的元素
2.7、findFirst 和 findAny:返回流中第一個(gè)或任意一個(gè)元素
三、并行流
四、Optional
五、擴(kuò)展流處理
首頁 Java java教程 Java8中如何使用Stream串流程式設(shè)計(jì)

Java8中如何使用Stream串流程式設(shè)計(jì)

May 07, 2023 pm 05:16 PM
java stream

一、Stream中間操作

Stream的中間操作是指在流鏈當(dāng)中,可以對(duì)資料進(jìn)行處理操作,包括filter過濾、map映射轉(zhuǎn)換、flatMap合併、distinct去重、sorted排序等操作。這些操作都會(huì)傳回一個(gè)新的Stream流對(duì)象,可以透過鍊式呼叫多個(gè)中間操作進(jìn)行複雜的資料處理。需要注意的是,中間操作需要具有終止操作才會(huì)觸發(fā)。

下面以類別來講解Stream常見的中間操作。

1.1、filter:過濾出符合條件的元素

filter()方法常用於實(shí)現(xiàn)資料過濾,即可以對(duì)集合、陣列等資料來源篩選出符合指定條件的元素,並返回一個(gè)新的流。

假設(shè)有一個(gè)黑名單手機(jī)號(hào)碼列表,需要篩選出其中所有開頭為「133」的元素,那麼可以透過filter()實(shí)作——

//將數(shù)組轉(zhuǎn)換為一個(gè)字符串列表
List<String> numbers = Arrays.asList("13378520000","13278520000","13178520000","13358520000");
//通過stream()方法創(chuàng)建一個(gè)流,接著使用filter()方法過濾出前綴為“133”的元素,最終通過collect() 方法將結(jié)果收集到一個(gè)新列表中
List<String> filterdNumbers = numbers.stream().filter(s -> s.startsWith("133")).collect(Collectors.toList());
System.out.println(filterdNumbers);


//打印結(jié)果:[13378520000, 13358520000]

1.2、map:映射轉(zhuǎn)換元素

map()方法用於對(duì)流中的每個(gè)元素進(jìn)行映射操作,將其轉(zhuǎn)換為另一個(gè)元素或提取其中的信息,並傳回一個(gè)新的流。

根據(jù)以下兩個(gè)案例分別學(xué)習(xí)map()將元素轉(zhuǎn)換為另一個(gè)元素以及提取元素其中的信息——

1.2.1、轉(zhuǎn)換元素

假設(shè)有一個(gè)手機(jī)號(hào)字元列表,需要根據(jù)前7位來確定手機(jī)號(hào)歸屬地,那麼就需要取得所有手機(jī)號(hào)前7位子字串,可以使用map()方法實(shí)現(xiàn):

List<String> numbers = Arrays.asList("13378520000","13278520000","13178520000","13558520000");
//通過stream()方法創(chuàng)建一個(gè)流,使用map()方法將每個(gè)字符串轉(zhuǎn)換為截取前7位的字符,最后使用collect()方法將結(jié)果收集到一個(gè)新列表中
List<String> filterdNumbers = numbers.stream().map(s -> s.substring(0,7)).collect(Collectors.toList());
System.out.println(filterdNumbers);


//打印結(jié)果:[1337852, 1327852, 1317852, 1355852]

1.2.2、提取元素資訊

假設(shè)有一個(gè)使用者物件列表,我們需要提取其中每個(gè)物件的手機(jī)號(hào),可以使用map()方法實(shí)作:

List<People> peopleList = Arrays.asList(
        new People("王二","13378520000"),
        new People("李二","13278520000"),
        new People("張四","13178520000")
);
//通過stream()方法創(chuàng)建一個(gè)流,使用map()方法提取每個(gè)用戶的手機(jī)號(hào),最后使用collect()方法將結(jié)果收集到一個(gè)新列表中
List<String> tel = peopleList.stream().map(People::getTel).collect(Collectors.toList());
System.out.println(tel);


//打印結(jié)果:[13378520000, 13278520000, 13178520000]

1.3、flatMap:將多個(gè)流合併為一個(gè)流

flatMap()方法可以實(shí)現(xiàn)多對(duì)多的映射,或者將多個(gè)列表合併成一個(gè)列表操作。

1.3.1、實(shí)現(xiàn)多對(duì)多的對(duì)應(yīng)

假設(shè)有兩組餘額清單A和B,需要將A組每個(gè)元素都與B組所有元素依序進(jìn)行相加,可以使用flatMap實(shí)作該多對(duì)多的映射——

List<Integer> listA = Arrays.asList(1, 2, 3);
List<Integer> listB = Arrays.asList(4, 5, 6);
List<Integer> list = listA.stream().flatMap(a -> listB.stream().map(b -> a +b)).collect(Collectors.toList());
System.out.println(list);


//打印結(jié)果:  [5, 6, 7, 6, 7, 8, 7, 8, 9]	

1.3.2、將多個(gè)列表合併成一個(gè)列表

#假設(shè)有一個(gè)包含多個(gè)手機(jī)號(hào)字串列表的列表,現(xiàn)在需要合併所有手機(jī)號(hào)字串成為一個(gè)列表,可以使用flatMap()方法實(shí)現(xiàn):

List<List<String>> listOfLists = Arrays.asList(
        Arrays.asList("13378520000", "13278520000"),
        Arrays.asList("13178520000", "13558520000"),
        Arrays.asList("15138510000", "15228310000")
);
List<String> flatMapList = listOfLists.stream().flatMap(Collection::stream).collect(Collectors.toList());
System.out.println(flatMapList);


//打印結(jié)果:[13378520000, 13278520000, 13178520000, 13558520000, 15138510000, 15228310000]

1.4、distinct:去除重複的元素

distinct()方法可以用來移除流中的重複元素,產(chǎn)生無重複的列表。

假設(shè)有一個(gè)包含重複手機(jī)號(hào)字串的列表,可以使用distinct()去重操作——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15138510000");
List<String> disNumbers = numbers.stream().distinct().collect(Collectors.toList());
System.out.println(disNumbers);		


//打印結(jié)果:[13378520000, 15138510000, 13178520000]		

注意一點(diǎn)的是,distinct用於針對(duì)流作去重操作時(shí),需要確定流中元素實(shí)現(xiàn)了equals()和hashCode()方法,因?yàn)檫@兩個(gè)方法是判斷兩個(gè)物件是否相等的標(biāo)準(zhǔn)。

1.5、sorted:排序元素

sorted()方法用於對(duì)流中的元素進(jìn)行排序。

假設(shè)需要對(duì)一組People物件依照年齡排序,以下分別依升序排序與降序排序——

1.5.1、升序排序





##預(yù)設(shè)情況下,是升序排序——

List<People> peopleList = Arrays.asList(
        new People("王二",20),
        new People("李二",30),
        new People("張四",31)
);
List<People> newpeopleList=peopleList.stream().sorted(Comparator.comparing(People::getAge)).collect(Collectors.toList());
//打印結(jié)果
newpeopleList.stream().forEach(System.out::println);

列印結(jié)果:

People{name='王二', age=20}
People {name='李二', age=30}

People{name='張四', age=31}

###1.5.2、降序排序##### #####透過reversed()方法進(jìn)行逆序排序,也就是將升序排序進(jìn)行倒序排序——###
List<People> peopleList = Arrays.asList(
        new People("王二",20),
        new People("李二",30),
        new People("張四",31)
);
List<People> newpeopleList = peopleList.stream().sorted(Comparator.comparing(People::getAge).reversed()).collect(Collectors.toList());
//打印結(jié)果
newpeopleList.stream().forEach(System.out::println);
###列印結(jié)果:########People{name='張四', age=31}###People{name='李二', age=30}###People{name='王二', age=20}#########1.6 、peek:查看每個(gè)元素的信息,但不修改流中元素的狀態(tài)######peek()方法用於查看流中的元素而不會(huì)修改流中元素的狀態(tài),可以在流中的任何階段使用,不會(huì)影響到流的操作,也不會(huì)終止流的操作。 ###
List<String> telList = Arrays.asList("13378520000","13278520000","13178520000","13558520000");
telList.stream().peek(t -> System.out.println(t))
        .map(t -> t.substring(0,3))
        .peek(t -> System.out.println(t))
        .collect(Collectors.toList());
###列印結(jié)果:#########?? ??? ??? ?13378520000###?? ????????? ??? ?132#########peek()方法和forEach很類似,都是可以用於遍歷流中的元素,但是,兩者之間存在著較大的差異。主要一點(diǎn)是,forEach在流中是一個(gè)終止操作,一旦調(diào)用它,就意味著Stream流已經(jīng)被處理完成,不能再進(jìn)行任何操作,例如,無法在forEach之後針對(duì)流進(jìn)行map、filter等操作,但peek方法可以,以上的案例可以看出,在第一次呼叫peek列印一個(gè)元素後,該元素還可以接著進(jìn)行map操作,進(jìn)行字串的前三位截取。 ######這是peek()方法和forEach最大的差別。 ###

1.7、limit 和 skip:截取流中的部分元素

limit()和skip()都是用于截取Stream流中部分元素的方法,兩者區(qū)別在于,limit()返回一個(gè)包含前n個(gè)元素的新流,skip()則返回一個(gè)丟棄前n個(gè)元素后剩余元素組成的新流。

int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
System.out.print("取數(shù)組前5個(gè)元素:");
Arrays.stream(arr).limit(5).forEach(n -> System.out.print(n + " ")); // 輸出結(jié)果為:1 2 3 4 5


System.out.print("跳過前3個(gè)元素,取剩余數(shù)組元素:");
Arrays.stream(arr).skip(3).forEach(n -> System.out.print(n + " ")); // 輸出結(jié)果為:4 5 6 7 8 9 10

二、Stream終止操作

Stream的終止操作是指執(zhí)行Stream流鏈中最后一個(gè)步驟,到這一步就會(huì)結(jié)束整個(gè)流處理。在Java8中,Stream終止操作包括forEach、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst和findAny等。這些終止操作都有返回值。需要注意一點(diǎn)是,如果沒有執(zhí)行終止操作的話,Stream流是不會(huì)觸發(fā)執(zhí)行的,例如,一個(gè)沒有終止操作的peek()方法代碼是不會(huì)執(zhí)行進(jìn)而打印——

list.stream().peek(t -> System.out.println("ddd"))

當(dāng)加上終止操作話,例如加上collect,就會(huì)打印出“ddd”——

list.stream().peek(t -> System.out.println("ddd")).collect(Collectors.toList());

下面按類別分別講解各個(gè)終止操作的使用。

2.1、forEach:遍歷流中的每個(gè)元素

該forEach前面已經(jīng)提到,這里不做過多介紹。

2.2、count:統(tǒng)計(jì)流中元素的數(shù)量

count可以統(tǒng)計(jì)流中元素的數(shù)量并返回結(jié)果。

假設(shè)有一個(gè)包含多個(gè)手機(jī)號(hào)字符串的列表,需要統(tǒng)計(jì)去重后的手機(jī)號(hào)數(shù)量,就可以使用count方法——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15138510000");
long count = numbers.stream()
        .distinct()//去重
        .count();//統(tǒng)計(jì)去重后的手機(jī)號(hào)
System.out.println(count);


//打印結(jié)果:3

2.3、reduce:將流中的所有元素歸約成一個(gè)結(jié)果

reduce()可以將流中的所有元素根據(jù)指定規(guī)則歸約成一個(gè)結(jié)果,并將該結(jié)果返回。

常用語法格式如下:

Optional<T> result = stream.reduce(BinaryOperator<T> accumulator);

可見,reduce方法會(huì)返回一個(gè)Optional類型的值,表示歸約后的結(jié)果,需要通過get()方法獲取Optional里的值。

假設(shè)有一個(gè)包含多個(gè)手機(jī)號(hào)字符串的List列表,需要在去重之后,再將列表所有字符串拼按照逗號(hào)間隔接成一個(gè)字符串返回,那么就可以通過reduce來實(shí)現(xiàn)——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15138510000");
Optional result = numbers.stream()
        .distinct() //去重
        .reduce((a ,b) -> a+","+b);//指定規(guī)則為,相臨兩個(gè)字符通過逗號(hào)“,”間隔
System.out.println(result.get());

//打印結(jié)果:13378520000,15138510000,13178520000

2.4、collect:將流中的元素收集到一個(gè)容器中,并返回該容器

collect的作用是將流中的元素收集到一個(gè)新的容器中,返回該容器。打個(gè)比喻,它就像一個(gè)采摘水果的工人,負(fù)責(zé)將水果一個(gè)個(gè)采摘下來,然后放進(jìn)一個(gè)籃子里,最后將籃子交給你。我在前面的案例當(dāng)中,基本都有用到collect,例如前面2.1的filter過濾用法中的List filterdNumbers = numbers.stream().filter(s -> s.startsWith("133")).collect(Collectors.toList()),就是將過濾出前綴為“133”的字符串,將這些過濾處理后的元素交給collect這個(gè)終止操作。這時(shí)collect就像采摘水果的員工,把采摘為前綴“133”的“水果”通過toList()方法收集到一個(gè)新的List容器當(dāng)中,然后交給你。最后你就可以得到一個(gè)只裝著前綴為“133”的元素集合。

在Java8的collect方法中,除里toList()之外,還提供了例如toSet,toMap等方法滿足不同的場(chǎng)景,根據(jù)名字就可以知道,toSet()返回的是一個(gè)Set集合,toMap()返回的是一個(gè)Map集合。

2.5、min 和 max:找出流中的最小值和最大值

min和max用來查找流中的最小值和最大值。

假設(shè)需要在查找出用戶列表中年齡最小的用戶,可以按照以下代碼實(shí)現(xiàn)——

List<People> peopleList = Arrays.asList(
        new People("王二",20),
        new People("李二",30),
        new People("張四",31)
);
//查找年齡最小的用戶,若沒有則返回一個(gè)null
People people = peopleList.stream().min(Comparator.comparing(People::getAge)).orElse(null);
System.out.println(people);

//打印結(jié)果:People{name=&#39;王二&#39;, age=20}

max的用法類似,這里不做額外說明。

2.6、anyMatch、allMatch 和 noneMatch:判斷流中是否存在滿足指定條件的元素

2.6.1、anyMatch

anyMatch用于判斷,如果流中至少有一個(gè)元素滿足給定條件,那么返回true,反之返回false,即 true||false為true這類的判斷。

假設(shè)在一個(gè)手機(jī)號(hào)字符串的List列表當(dāng)中,判斷是否包含前綴為“153”的手機(jī)號(hào),就可以使用anyMatch——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15338510000");
boolean hasNum = numbers.stream().anyMatch(n -> n.startsWith("153"));
System.out.println(hasNum);

//打印結(jié)果:true

2.6.2、allMatch

allMatch用于判斷,流中的所有元素是否都滿足給定條件,滿足返回true,反之false,即true&&false為false這類判斷。

假設(shè)在一個(gè)手機(jī)號(hào)字符串的List列表當(dāng)中,判斷手機(jī)號(hào)是否都滿足前綴為“153”的手機(jī)號(hào),就可以用allMatch——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "15338510000");
boolean hasNum = numbers.stream().allMatch(n -> n.startsWith("153"));
System.out.println(hasNum);

//打印結(jié)果:false

2.6.3、noneMatch

noneMatch用于判斷,如果流中沒有任何元素滿足給定的條件,返回true,如果流中有任意一個(gè)條件滿足給定條件,返回false,類似!true為false的判斷。

假設(shè)在一個(gè)手機(jī)號(hào)字符串的List列表當(dāng)中,判斷手機(jī)號(hào)是否都不滿足前綴為“153”的手機(jī)號(hào),就可以用noneMatch——

List<String> numbers = Arrays.asList("13378520000", "15138510000","13178520000", "1238510000");
//numbers里沒有前綴為“153”的手機(jī)號(hào)
boolean hasNum = numbers.stream().noneMatch(n -> n.startsWith("153"));
System.out.println(hasNum);


//打印結(jié)果:true

這三個(gè)方法其實(shí)存在一定互相替代性,例如在3.6.1中,滿足!anyMatch表示所有手機(jī)號(hào)都不為“153”前綴,才得到true,這不就是noneMatch,主要看在項(xiàng)目當(dāng)中如何靈活應(yīng)用。

2.7、findFirst 和 findAny:返回流中第一個(gè)或任意一個(gè)元素

2.7.1、findFirst

findFirst用于返回流中第一個(gè)元素,如果流為空話,則返回一個(gè)空的Optional對(duì)象——

假設(shè)需要對(duì)一批同手機(jī)號(hào)的黑名單用戶按照時(shí)間戳降序排序,然后取出第一個(gè)即時(shí)間戳為最早的用戶,就可以使用findFirst——

List<People> peopleList = Arrays.asList(
        new People("王二","13178520000","20210409"),
        new People("李二","13178520000","20230401"),
        new People("張四","13178520000","20220509"),
        new People("趙六","13178520000","20220109")
);
/**
 * 先按照時(shí)間升序排序,排序后的結(jié)果如下:
 *   People{name=&#39;王二&#39;, tel=&#39;13178520000&#39;, time=&#39;20210409&#39;}
 *   People{name=&#39;趙六&#39;, tel=&#39;13178520000&#39;, time=&#39;20220109&#39;}
 *   People{name=&#39;張四&#39;, tel=&#39;13178520000&#39;, time=&#39;20220509&#39;}
 *   People{name=&#39;李二&#39;, tel=&#39;13178520000&#39;, time=&#39;20230401&#39;}
 *
 *排序后,People{name=&#39;王二&#39;, tel=&#39;13178520000&#39;, time=&#39;20210409&#39;}成了流中的第一個(gè)元素
 */
People people = peopleList.stream().sorted(Comparator.comparing(People::getTime)).findFirst().orElse(null);
System.out.println(people);

//打印結(jié)果:People{name=&#39;王二&#39;, tel=&#39;13178520000&#39;, time=&#39;20210409&#39;}

2.7.2、findAny

findAny返回流中的任意一個(gè)元素,如果流為空,則通過Optional對(duì)象返回一個(gè)null。

假設(shè)有一個(gè)已經(jīng)存在的黑名單手機(jī)號(hào)列表blackList,現(xiàn)在有一批新的手機(jī)號(hào)列表phoneNumber,需要基于blackList列表過濾出phoneNumber存在的黑名單手機(jī)號(hào),最后從過濾出來的黑名單手機(jī)號(hào)當(dāng)中挑選出來出來任意一個(gè),即可以通過findAny實(shí)現(xiàn)——

//blackList是已經(jīng)存在的黑名單列表
List<String> blackList = Arrays.asList("13378520000", "15138510000");
//新來的手機(jī)號(hào)列表
List<String> phoneNumber = Arrays.asList("13378520000", "13178520000", "1238510000","15138510000","13299920000");
String blackPhone = phoneNumber.stream()
        //過濾出phoneNumber有包含在blackList的手機(jī)號(hào),這類手機(jī)號(hào)即為黑名單手機(jī)號(hào)。
        .filter(phone -> blackList.contains(phone))
        //獲取過濾確定為黑名單手機(jī)號(hào)的任意一個(gè)
        .findAny()
        //如果沒有則返回一個(gè)null
        .orElse(null);
System.out.println(blackPhone);

//打印結(jié)果:13378520000

三、并行流

前面的案例主要都是以順序流來講解,接下來,就是講解Stream的并行流。在大數(shù)據(jù)量處理場(chǎng)景下,使用并行流可以提高某些操作效率,但同樣存在一些需要考慮的問題,并非所有情況下都可以使用。

3.1、什么是并行流:并行流的概念和原理

并行流是指通過將數(shù)據(jù)按照一定的方式劃分成多個(gè)片段分別在多個(gè)處理器上并行執(zhí)行,這就意味著,可能處理完成的數(shù)據(jù)順序與原先排序好的數(shù)據(jù)情況是不一致的。主要是用在比較大的數(shù)據(jù)量處理情況,若數(shù)據(jù)量太少,效率并不比順序流要高,因?yàn)榈讓悠鋵?shí)就使用到了多線程的技術(shù)。

并行流的流程原理如下:

1、輸入數(shù)據(jù):并行流的初始數(shù)據(jù)一般是集合或者數(shù)組,例如Arrays.asList("13378520000", "13178520000", "1238510000","15138510000","13299920000");

2、劃分?jǐn)?shù)據(jù):將初始數(shù)據(jù)平均分成若干個(gè)子集,每個(gè)子集可以在不同的線程中獨(dú)立進(jìn)行處理,這個(gè)過程通常叫“分支”(Forking),默認(rèn)情況下,Java8并行流使用到了ForkJoinPool框架,會(huì)將Arrays.asList("13378520000", "13178520000", "1238510000","15138510000","13299920000")劃分成更小的顆粒進(jìn)行處理,可能會(huì)將該數(shù)組劃分成以下三個(gè)子集:

[13378520000, 13178520000] [1238510000, 13338510000] [13299920000]

3、處理數(shù)據(jù):針對(duì)劃分好的子集并行進(jìn)行相同的操作,例如包括過濾(filter)、映射(map)、去重(distinct)等,這個(gè)過程通常叫“計(jì)算”(Computing),例如需要過濾為前綴包括“133”的字符集合,那么,各個(gè)子集,就會(huì)處理得到以下結(jié)果:

[13378520000] [13338510000] []

4、合并結(jié)果:將所有子集處理完成的結(jié)果進(jìn)行匯總,得到最終結(jié)果。這個(gè)過程通常叫“合并”(Merging),結(jié)果就會(huì)合并如下:

[13378520000,13338510000]

5、返回結(jié)果:返回最終結(jié)果。

通俗而言,就是順序流中,只有一個(gè)工人在摘水果,并行流中,是多個(gè)工人同時(shí)在摘水果。

3.2、創(chuàng)建并行流:通過 parallel() 方法將串行流轉(zhuǎn)換為并行流

可以通過parallel()方法將順序流轉(zhuǎn)換為并行流,操作很簡(jiǎn)單,只需要在順序流上調(diào)用parallel()即可。

List<String> numbers = Arrays.asList("13378360000","13278240000","13178590000","13558120000");
//通過stream().parallel()方法創(chuàng)建一個(gè)并行流,使用map()方法將每個(gè)字符串轉(zhuǎn)換為截取前7位的字符,最后使用collect()方法將結(jié)果收集到一個(gè)新列表中
List<String> filNums = numbers.stream().parallel().map(s -> s.substring(0,7)).collect(Collectors.toList());
System.out.println(filNums);


//打印結(jié)果:[1337836, 1327824, 1317859, 1355812]

3.3、并行流的注意事項(xiàng):并行流可能引發(fā)的線程安全,以及如何避免這些問題

在使用并發(fā)流的過程中,可能會(huì)引發(fā)以下線程安全問題:并行流中的每個(gè)子集都在不同線程運(yùn)行,可能會(huì)導(dǎo)致對(duì)共享狀態(tài)的競(jìng)爭(zhēng)和沖突。

避免線程問題的方法如下:避免修改共享狀態(tài),即在處理集合過程當(dāng)中,避免被其他線程修改集合數(shù)據(jù),可以使用鎖來保證線程安全。

使用無狀態(tài)操作:在并行流處理過程盡量使用無狀態(tài)操作,例如filter、map之類的,可以盡量避免線程安全和同步問題。

四、Optional

4.1、什么是 Optional:Optional 類型的作用和使用場(chǎng)景

在實(shí)際開發(fā)當(dāng)中,Optional類型通常用于返回可能為空的方法、避免null值的傳遞和簡(jiǎn)化復(fù)雜的判斷邏輯等場(chǎng)景。調(diào)用Optional對(duì)象的方法,需要通過isPresent()方法判斷值是否存在,如果存在則可以通過get()方法獲取其值,如果不存在則可以通過orElse()方法提供默認(rèn)值,或者拋出自定義異常處理。

4.2、如何使用 Optional:如何使用 Optional 類型

使用Optional類型主要目的是在數(shù)據(jù)可能為空的情況下,提供一種更安全、更優(yōu)雅的處理方式。

以下是使用Optional類型的常用方法:

4.2.1、ofNullable()和isPresent()方法

將一個(gè)可能為null的對(duì)象包裝成Optional類型的對(duì)象,然后根據(jù)isPresent方法判斷對(duì)象是否包含空值——

String str = null;
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional對(duì)象不為空");
}else {
    System.out.println("Optional對(duì)象為空");
}

//打印結(jié)果:Optional對(duì)象為空

4.2.2、get()方法

獲取Optional對(duì)象中的值,如果對(duì)象為空則拋出NoSuchElementException異常——

String str = null;
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional對(duì)象不為空");
}else {
    System.out.println("Optional對(duì)象為空");
    optStr.get();
}

控制臺(tái)打印結(jié)果:

Exception in thread "main" java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
at com.zhu.fte.biz.test.StreamTest.main(StreamTest.java:144)
Optional對(duì)象為空

4.2.4、orElse()方法

獲取Optional對(duì)象中的值,如果對(duì)象為空則返回指定的默認(rèn)值——

String str = null;
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional對(duì)象不為空");
}else {
    System.out.println("Optional對(duì)象為空,返回默認(rèn)值:" + optStr.orElse("null"));
}


//打印結(jié)果:Optional對(duì)象為空,返回默認(rèn)值:null

當(dāng)然,如果不為空的話,則能正常獲取對(duì)象中的值——

String str = "測(cè)試";
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional對(duì)象不為空,返回值:" + optStr.orElse("null"));
}else {
    System.out.println("Optional對(duì)象為空,返回默認(rèn)值:" + optStr.orElse("null"));
}

//打印結(jié)果:Optional對(duì)象不為空,返回值:測(cè)試

那么,問題來了,它是否能判斷“ ”這類空格的字符串呢,我實(shí)驗(yàn)了一下,

String str = "     ";
Optional<String> optStr = Optional.ofNullable(str);
if (optStr.isPresent()){
    System.out.println("Optional對(duì)象不為空,返回值:" + optStr.orElse("null"));
}else {
    System.out.println("Optional對(duì)象為空,返回默認(rèn)值:" + optStr.orElse("null"));
}


//打印結(jié)果:Optional對(duì)象不為空,返回值:

可見,這類空字符串,在orElse判斷當(dāng)中,跟StringUtils.isEmpty()類似,都是把它當(dāng)成非空字符串,但是StringUtils.isBlank()則判斷為空字符串。

4.2.5、orElseGet()方法

orElseGet()和orElse()類似,都可以提供一個(gè)默認(rèn)值。兩者區(qū)別在于,orElse方法在每次調(diào)用時(shí)都會(huì)創(chuàng)建默認(rèn)值,而orElseGet只在需要時(shí)才會(huì)創(chuàng)建默認(rèn)值。

4.3、Optional 和 null 的區(qū)別: Optional 類型與 null 值的異同

兩者都可以表示缺失值的情況,兩者主要區(qū)別為:Optional類型是一種包裝器對(duì)象,可以將一個(gè)可能為空的對(duì)象包裝成一個(gè)Optional對(duì)象。這個(gè)對(duì)象可以通過調(diào)用ofNullable()、of()或其他方法來創(chuàng)建。而null值則只是一個(gè)空引用,沒有任何實(shí)際的值。

Optional類型還可以避免出現(xiàn)NullPointerException異常,具體代碼案例如下:

String str = null;
//錯(cuò)誤示范:直接調(diào)用str.length()方法會(huì)觸發(fā)NullPointerException
//int length = str.length()

//通過Optional類型避免NullPointerException
Optional<String> optionalStr = Optional.ofNullable(str);
if (optionalStr.isPresent()){//判斷Optional對(duì)象是否都包含非空值
    int length = optionalStr.get().length();
    System.out.println("字符串長(zhǎng)度為:" + length);
}else {
    System.out.println("字符串為空!");
}

//使用map()方法對(duì)Optional對(duì)象進(jìn)行轉(zhuǎn)換時(shí),確保返回對(duì)結(jié)果不為null
Optional<Integer> optionalLength = optionalStr.map(s -> s.length());
System.out.println("字符串長(zhǎng)度為:" + optionalLength.orElse(-1)); // 使用orElse()方法提供默認(rèn)值

五、擴(kuò)展流處理

除里以上常用的流處理之外,Java8還新增了一些專門用來處理基本類型的流,例如IntStream、LongStream、DoubleStream等,其對(duì)應(yīng)的Api接口基本與前面案例相似,讀者可以自行研究。

最后,需要注意一點(diǎn)是,在流處理過程當(dāng)中,盡量使用原始類型數(shù)據(jù),避免裝箱操作,因?yàn)檠b箱過程會(huì)有性能開銷、內(nèi)存占用等問題,例如,當(dāng)原始數(shù)據(jù)int類型被裝箱成Integer包裝類型時(shí),這個(gè)過程會(huì)涉及到對(duì)象的創(chuàng)建、初始化、垃圾回收等過程,需要額外的性能開銷。

以上是Java8中如何使用Stream串流程式設(shè)計(jì)的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請(qǐng)聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)程式碼編輯軟體(SublimeText3)

如何在Java的地圖上迭代? 如何在Java的地圖上迭代? Jul 13, 2025 am 02:54 AM

遍歷Java中的Map有三種常用方法:1.使用entrySet同時(shí)獲取鍵和值,適用於大多數(shù)場(chǎng)景;2.使用keySet或values分別遍歷鍵或值;3.使用Java8的forEach簡(jiǎn)化代碼結(jié)構(gòu)。 entrySet返回包含所有鍵值對(duì)的Set集合,每次循環(huán)獲取Map.Entry對(duì)象,適合頻繁訪問鍵和值的情況;若只需鍵或值,可分別調(diào)用keySet()或values(),也可在遍歷鍵時(shí)通過map.get(key)獲取值;Java8中可通過Lambda表達(dá)式使用forEach((key,value)-&gt

Java中的可比較與比較器 Java中的可比較與比較器 Jul 13, 2025 am 02:31 AM

在Java中,Comparable用於類內(nèi)部定義默認(rèn)排序規(guī)則,Comparator用於外部靈活定義多種排序邏輯。 1.Comparable是類自身實(shí)現(xiàn)的接口,通過重寫compareTo()方法定義自然順序,適用於類有固定、最常用的排序方式,如String或Integer。 2.Comparator是外部定義的函數(shù)式接口,通過compare()方法實(shí)現(xiàn),適合同一類需要多種排序方式、無法修改類源碼或排序邏輯經(jīng)常變化的情況。兩者區(qū)別在於Comparable只能定義一種排序邏輯且需修改類本身,而Compar

如何處理Java中的字符編碼問題? 如何處理Java中的字符編碼問題? Jul 13, 2025 am 02:46 AM

處理Java中的字符編碼問題,關(guān)鍵是在每一步都明確指定使用的編碼。 1.讀寫文本時(shí)始終指定編碼,使用InputStreamReader和OutputStreamWriter並傳入明確的字符集,避免依賴系統(tǒng)默認(rèn)編碼。 2.在網(wǎng)絡(luò)邊界處理字符串時(shí)確保兩端一致,設(shè)置正確的Content-Type頭並用庫(kù)顯式指定編碼。 3.謹(jǐn)慎使用String.getBytes()和newString(byte[]),應(yīng)始終手動(dòng)指定StandardCharsets.UTF_8以避免平臺(tái)差異導(dǎo)致的數(shù)據(jù)損壞??傊?,通過在每個(gè)階段

JavaScript數(shù)據(jù)類型:原始與參考 JavaScript數(shù)據(jù)類型:原始與參考 Jul 13, 2025 am 02:43 AM

JavaScript的數(shù)據(jù)類型分為原始類型和引用類型。原始類型包括string、number、boolean、null、undefined和symbol,其值不可變且賦值時(shí)復(fù)制副本,因此互不影響;引用類型如對(duì)象、數(shù)組和函數(shù)存儲(chǔ)的是內(nèi)存地址,指向同一對(duì)象的變量會(huì)相互影響。判斷類型可用typeof和instanceof,但需注意typeofnull的歷史問題。理解這兩類差異有助於編寫更穩(wěn)定可靠的代碼。

Hashmap在Java內(nèi)部如何工作? Hashmap在Java內(nèi)部如何工作? Jul 15, 2025 am 03:10 AM

HashMap在Java中通過哈希表實(shí)現(xiàn)鍵值對(duì)存儲(chǔ),其核心在於快速定位數(shù)據(jù)位置。 1.首先使用鍵的hashCode()方法生成哈希值,並通過位運(yùn)算轉(zhuǎn)換為數(shù)組索引;2.不同對(duì)象可能產(chǎn)生相同哈希值,導(dǎo)致衝突,此時(shí)以鍊錶形式掛載節(jié)點(diǎn),JDK8後鍊錶過長(zhǎng)(默認(rèn)長(zhǎng)度8)則轉(zhuǎn)為紅黑樹提升效率;3.使用自定義類作鍵時(shí)必須重寫equals()和hashCode()方法;4.HashMap動(dòng)態(tài)擴(kuò)容,當(dāng)元素?cái)?shù)超過容量乘以負(fù)載因子(默認(rèn)0.75)時(shí),擴(kuò)容並重新哈希;5.HashMap非線程安全,多線程下應(yīng)使用Concu

Java中的'靜態(tài)”關(guān)鍵字是什麼? Java中的'靜態(tài)”關(guān)鍵字是什麼? Jul 13, 2025 am 02:51 AM

InJava,thestatickeywordmeansamemberbelongstotheclassitself,nottoinstances.Staticvariablesaresharedacrossallinstancesandaccessedwithoutobjectcreation,usefulforglobaltrackingorconstants.Staticmethodsoperateattheclasslevel,cannotaccessnon-staticmembers,

在C中使用std :: Chrono 在C中使用std :: Chrono Jul 15, 2025 am 01:30 AM

std::chrono在C 中用於處理時(shí)間,包括獲取當(dāng)前時(shí)間、測(cè)量執(zhí)行時(shí)間、操作時(shí)間點(diǎn)與持續(xù)時(shí)間及格式化解析時(shí)間。 1.獲取當(dāng)前時(shí)間使用std::chrono::system_clock::now(),可轉(zhuǎn)換為可讀字符串但係統(tǒng)時(shí)鐘可能不單調(diào);2.測(cè)量執(zhí)行時(shí)間應(yīng)使用std::chrono::steady_clock以確保單調(diào)性,並通過duration_cast轉(zhuǎn)換為毫秒、秒等單位;3.時(shí)間點(diǎn)(time_point)和持續(xù)時(shí)間(duration)可相互操作,但需注意單位兼容性和時(shí)鐘紀(jì)元(epoch)

什麼是Java的重新進(jìn)入? 什麼是Java的重新進(jìn)入? Jul 13, 2025 am 02:14 AM

ReentrantLock在Java中提供比synchronized更靈活的線程控制。 1.它支持非阻塞獲取鎖(tryLock())、帶超時(shí)的鎖獲取(tryLock(longtimeout,TimeUnitunit))和可中斷等待鎖;2.允許設(shè)置公平鎖,避免線程飢餓;3.支持多個(gè)條件變量,實(shí)現(xiàn)更精細(xì)的等待/通知機(jī)制;4.需手動(dòng)釋放鎖,必須在finally塊中調(diào)用unlock()以避免資源洩漏;5.適用於需要高級(jí)同步控制的場(chǎng)景,如自定義同步工具或複雜並發(fā)結(jié)構(gòu),但對(duì)簡(jiǎn)單互斥需求仍推薦使用synchro

See all articles