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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java -- Stream流用法

發布時間:2023/11/16 java 45 coder
生活随笔 收集整理的這篇文章主要介紹了 Java -- Stream流用法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 前言

流是Java 8 API添加的一個新的抽象,稱為流Stream,以一種聲明性方式處理數據集合,側重對于源數據計算能力的封裝,并且支持序列與并行兩種操作方式。
Stream流是從支持數據處理操作的源生成的元素序列,源可以是數組、文件、集合、函數。流不是集合元素,它不是數據結構并不保存數據,它的主要目的在于計算。
Stream流是對集合(Collection)對象功能的增強,與Lambda表達式結合,可以提高編程效率、間接性和程序可讀性。

2. 操作符

流的操作類型主要分為兩種:中間操作符、終端操作符

3 中間操作符

通常對于Stream的中間操作,可以視為是源的查詢,并且是懶惰式的設計,對于源數據進行的計算只有在需要時才會被執行,與數據庫中視圖的原理相似;
Stream流的強大之處便是在于提供了豐富的中間操作,相比集合或數組這類容器,極大的簡化源數據的計算復雜度
一個流可以跟隨零個或多個中間操作。其目的主要是打開流,做出某種程度的數據映射/過濾,然后返回一個新的流,交給下一個操作使用
這類操作都是惰性化的,僅僅調用到這類方法,并沒有真正開始流的遍歷,真正的遍歷需等到終端操作時,常見的中間操作有下面即將介紹的 filter、map 等
紹的 filter、map 等

流方法 含義 備注
filter 用于通過設置的條件過濾出元素
sorted 返回排序后的流
map 接受一個函數作為參數。這個函數會被應用到每個元素上,并將其映射成一個新的元素(使用映射一詞,是因為它和轉換類似,但其中的細微差別在于它是“創建一個新版本”而不是去“修改”)
distinct 返回一個元素各異(根據流所生成元素的hashCode和equals方法實現)的流
....

示例代碼如下:

public static void main(String[] args) {
	List<Person> list = new ArrayList<>();

	// 名字 + 年齡。注意所有人的年齡有相同的
	list.add(new Person("張三", 21));
	list.add(new Person("張四", 21));

	list.add(new Person("李三", 28));
	list.add(new Person("李四", 28));

	list.add(new Person("趙三", 23));
	list.add(new Person("趙四", 23));
}

3.1 filter 過濾操作

用于通過設置的條件過濾出元素

// 注意 filter 的結果為true才會留下這條數據
// 同時filter是中間操作,不是最終操作
List<Person> personList = list.stream().filter((person) -> person.getAge() > 25).collect(Collectors.toList());
System.out.println(personList);

結果
[Person(name=李三, age=28), Person(name=李四, age=28)]

3.2 sorted 排序操作

返回排序后的流

// 正序排序
List<Person> personList = list.stream().sorted((x, y) -> x.getAge().compareTo(y.getAge())).collect(Collectors.toList());
System.out.println(personList);

// 倒序排序
List<Person> personList1 = list.stream().sorted((x, y) -> y.getAge().compareTo(x.getAge())).collect(Collectors.toList());
System.out.println(personList1);

結果
[Person(name=張三, age=21), Person(name=張四, age=21), Person(name=趙三, age=23), Person(name=趙四, age=23), Person(name=李三, age=28), Person(name=李四, age=28)]
[Person(name=李三, age=28), Person(name=李四, age=28), Person(name=趙三, age=23), Person(name=趙四, age=23), Person(name=張三, age=21), Person(name=張四, age=21)]

3.3 map 操作

接受一個函數作為參數。這個函數會被應用到每個元素上,并將其映射成一個新的元素(使用映射一詞,是因為它和轉換類似,但其中的細微差別在于它是“創建一個新版本”而不是去“修改”)
這是一個非常好用的操作,一定要重視

本質map是接受了一個Function的函數,如下:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
我們傳進去key,按照一定規則給我們返回val

List<Integer> collect = list.stream().map(person -> person.getAge()).collect(Collectors.toList());
System.out.println(collect);

Set<Integer> collect1 = list.stream().map(person -> person.getAge()).collect(Collectors.toSet());
System.out.println(collect1);

結果
[21, 21, 28, 28, 23, 23]
[21, 23, 28]

3.4 distinct 去重操作

返回一個元素各異(根據流所生成元素的hashCode和equals方法實現)的流

// 存在重復的年齡,去重
List<Integer> collect = list.stream().map(person -> person.getAge()).distinct().collect(Collectors.toList());
System.out.println(collect);

結果
[21, 28, 23]

4 終端操作符

Stream流執行完終端操作之后,無法再執行其他動作,否則會報狀態異常,提示該流已經被執行操作或者被關閉,想要再次執行操作必須重新創建Stream流
一個流有且只能有一個終端操作,當這個操作執行后,流就被關閉了,無法再被操作,因此一個流只能被遍歷一次,若想在遍歷需要通過源數據在生成流。
終端操作的執行,才會真正開始流的遍歷。如 count、collect 等

流方法 含義 備注
max 最大值
min 最小值
sum 求和
count 返回流中元素總數
findFirst 返回第一個元素
findAny 將返回當前流中的任意元素(注意為了效率會返回第一個符合的元素)
forEach 遍歷流
reduce 可以將流中元素反復結合起來,得到一個值
collect 收集器,將流轉換為其他形式 這個重點掌握,后面詳細介紹
....

4.1 max操作

獲取數據流中最大值

Person person = list.stream().max((o1, o2) -> o1.getAge().compareTo(o2.getAge())).get();
System.out.println(person);

結果
Person(name=李三, age=28)

4.2 min操作

獲取數據流中最小值

Person person = list.stream().min((o1, o2) -> o1.getAge().compareTo(o2.getAge())).get();
System.out.println(person);

結果
Person(name=張三, age=21)

4.3 sum操作

求和

// 注意sum 必須是IntStream流才可以使用
int sum = list.stream().mapToInt(x -> x.getAge()).sum();
System.out.println(sum);

結果
144

4.4 count操作

求和

// 相當于list.size
long count = list.stream().count();
System.out.println("size = " + list.size() + ",  count = " + count);

結果
size = 6,  count = 6

4.5 findFirst操作

求和

Person person = list.stream().findFirst().get();
System.out.println(person);

結果
Person(name=張三, age=21)

4.6 findAny操作

求和

// 注意。findAny一定返回符合規則的第一個,因為其是流,所以為了效率,找到第一個,就立馬返回
Person person = list.stream().findAny().get();
System.out.println(person);

結果
Person(name=張三, age=21)

4.7 forEach操作

求和

list.stream().forEach(person -> {
	// 類似于for循環,可以做很多操作
	// 如果年齡大于25,return相當于for循環的continue
	if (person.getAge() > 25) {
		return;
	}
	System.out.println(person);
});

結果
Person(name=張三, age=21)
Person(name=張四, age=21)
Person(name=趙三, age=23)
Person(name=趙四, age=23)

4.8 reduce操作

可以將流中元素反復結合起來,得到一個值。
個人感覺reduce實用性并不是很好,并且理解成本挺高的,不建議使用

// 1. a + b ==> 賦值給 下一輪的a
// 2. (a + b) + b == > 賦值給 下一輪的a
// 相當于 sum = a + b + c + d + ....
int sum = list.stream().map(Person::getAge).reduce((a, b) -> {
	System.out.println("a = " + a + "  b = " + b);
	return a + b;
}).get();
System.out.println("sum = " + sum);

結果
a = 21  b = 21
a = 42  b = 28
a = 70  b = 28
a = 98  b = 23
a = 121  b = 23
sum = 144

4.9 collect操作

收集器,將流轉換為其他形式
非常重要的一個參數。后面會詳細舉例,一定要搞懂,尤其針對于toList,toMap等常見操作

// 相當于new了一個新的list
List<Person> collect = list.stream().collect(Collectors.toList());
System.out.println(collect);

結果
[Person(name=張三, age=21), Person(name=張四, age=21), Person(name=李三, age=28), Person(name=李四, age=28), Person(name=趙三, age=23), Person(name=趙四, age=23)]

5 Collect收集

Collector:結果收集策略的核心接口,具備將指定元素累加存放到結果容器中的能力;
并在Collectors工具中提供了Collector接口的實現類

// collect請求參數是Collector,Collector是一個接口
<R, A> R collect(Collector<? super T, A, R> collector);

Collectors是一個工具類,里面有Collector的具體實現類
/**
 * Simple implementation class for {@code Collector}.
 *
 * @param <T> the type of elements to be collected
 * @param <R> the type of the result
 */
static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
    private final Supplier<A> supplier;
    private final BiConsumer<A, T> accumulator;
    private final BinaryOperator<A> combiner;
    private final Function<A, R> finisher;
    private final Set<Characteristics> characteristics;

    CollectorImpl(Supplier<A> supplier,
                  BiConsumer<A, T> accumulator,
                  BinaryOperator<A> combiner,
                  Function<A,R> finisher,
                  Set<Characteristics> characteristics) {
        this.supplier = supplier;
        this.accumulator = accumulator;
        this.combiner = combiner;
        this.finisher = finisher;
        this.characteristics = characteristics;
    }

    CollectorImpl(Supplier<A> supplier,
                  BiConsumer<A, T> accumulator,
                  BinaryOperator<A> combiner,
                  Set<Characteristics> characteristics) {
        this(supplier, accumulator, combiner, castingIdentity(), characteristics);
    }

    @Override
    public BiConsumer<A, T> accumulator() {
        return accumulator;
    }

    @Override
    public Supplier<A> supplier() {
        return supplier;
    }

    @Override
    public BinaryOperator<A> combiner() {
        return combiner;
    }

    @Override
    public Function<A, R> finisher() {
        return finisher;
    }

    @Override
    public Set<Characteristics> characteristics() {
        return characteristics;
    }
}

5.1 toList操作

它將輸入元素累積到一個新的List中。對于返回的List的類型、可變性、序列化能力或線程安全性并沒有保證;

// 我們可以看到,本質上,toList其實就是傳入了一個CollectorImpl的實現
public static <T>
Collector<T, ?, List<T>> toList() {
    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                               (left, right) -> { left.addAll(right); return left; },
                               CH_ID);
}

// 用法
List<Person> list1 = list.stream().collect(Collectors.toList());
System.out.println(list1);

// 結果
[Person(name=張三, age=21), Person(name=張四, age=21), Person(name=李三, age=28), Person(name=李四, age=28), Person(name=趙三, age=23), Person(name=趙四, age=23)]

5.2 toSet操作

它將把輸入元素累計到一個新的Set中。返回的Set的類型、可變性、序列化能力或線程安全性并沒有確保

// 用法
Set<Person> set = list.stream().collect(Collectors.toSet());
System.out.println(set);

// 結果
[Person(name=李四, age=28), Person(name=趙四, age=23), Person(name=張三, age=21), Person(name=趙三, age=23), Person(name=李三, age=28), Person(name=張四, age=21)]

5.3 toMap操作1

它將把輸入元素累計到一個Map中,這個Map的鍵和值都是通過對輸入元素應用給定的映射函數得到的

// 正常執行
Map<String, Person> map1 = list.stream().collect(Collectors.toMap(Person::getName, Function.identity()));
System.out.println(map1);

// 報錯 因為age是一個是重復的key
Map<Integer, Person> map2 = list.stream().collect(Collectors.toMap(Person::getAge, Function.identity()));
System.out.println(map2);

// 結果
{張四=Person(name=張四, age=21), 李四=Person(name=李四, age=28), 張三=Person(name=張三, age=21), 趙三=Person(name=趙三, age=23), 趙四=Person(name=趙四, age=23), 李三=Person(name=李三, age=28)}
Exception in thread "main" java.lang.IllegalStateException: Duplicate key Person(name=張三, age=21)
	at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
	at java.util.HashMap.merge(HashMap.java:1254)
	at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
	at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
	at java.util.LinkedList$LLSpliterator.forEachRemaining(LinkedList.java:1235)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)

5.3 toMap操作2

如果key重復了,解決key重復問題

// 如果重復key,k1
Map<Integer, Person> map1 = list.stream().collect(Collectors.toMap(Person::getAge, Function.identity(), (k1, k2) -> k1));
System.out.println("map1 = " + JSON.toJSONString(map1));

// 如果重復key,k2
Map<Integer, Person> map2 = list.stream().collect(Collectors.toMap(Person::getAge, Function.identity(), (k1, k2) -> k2));
System.out.println("map2 = " + JSON.toJSONString(map2));

// 結果 重點看下結果的選擇
map1 = {21:{"age":21,"name":"張三"},23:{"age":23,"name":"趙三"},28:{"age":28,"name":"李三"}}
map2 = {21:{"age":21,"name":"張四"},23:{"age":23,"name":"趙四"},28:{"age":28,"name":"李四"}}

5.3 toMap操作3

解決map返回的順序問題

// 返回無序的HashMap
Map<Integer, Person> map1 = list.stream().collect(Collectors.toMap(
		Person::getAge,
		Function.identity(),
		(k1, k2) -> k1,
		HashMap::new));
System.out.println("map1 = " + JSON.toJSONString(map1));

// 返回有序的LinkedHashMap
Map<Integer, Person> map2 = list.stream().collect(Collectors.toMap(
		Person::getAge,
		Function.identity(),
		(k1, k2) -> k1,
		LinkedHashMap::new));
System.out.println("map2 = " + JSON.toJSONString(map2));

// 結果 重點看下結果的選擇
map1 = {21:{"age":21,"name":"張三"},23:{"age":23,"name":"趙三"},28:{"age":28,"name":"李三"}}
map2 = {21:{"age":21,"name":"張三"},28:{"age":28,"name":"李三"},23:{"age":23,"name":"趙三"}}

5.4 joining

連接字符串

// 默認沒有字符連接
String s1 = list.stream().map(Person::getName).collect(Collectors.joining());
System.out.println("s1 = " + s1);

// 以-連接字符
String s2 = list.stream().map(Person::getName).collect(Collectors.joining("-"));
System.out.println("s2 = " + s2);

// 以-連接字符, 同時增加前綴和后綴
String s3 = list.stream().map(Person::getName).collect(Collectors.joining("-", "prefix", "suffix"));
System.out.println("s3 = " + s3);

// 結果 
s1 = 張三張四李三李四趙三趙四
s2 = 張三-張四-李三-李四-趙三-趙四
s3 = prefix張三-張四-李三-李四-趙三-趙四suffix

5.5 counting

計算list里面的數量

// 默認沒有字符連接
System.out.println("sum = " + list.size());

Long sum1 = list.stream().collect(Collectors.counting());
System.out.println("sum1 = " + sum1);

long sum2 = list.stream().count();
System.out.println("sum2 = " + sum2);

// 結果 
sum = 6
sum1 = 6
sum2 = 6

5.6 summarizingInt

統計一些常見的數據

IntSummaryStatistics statistics = list.stream().collect(Collectors.summarizingInt(x -> x.getAge()));
System.out.println(statistics);

// 結果 
IntSummaryStatistics{count=6, sum=144, min=21, average=24.000000, max=28}

5.7 groupingBy

它的作用是實現"分組"操作,根據給定的分類函數將輸入元素分組,并把分組的結果存儲在一個Map中并返回。

// key是age,value是list
Map<Integer, List<Person>> map1 = list.stream().collect(Collectors.groupingBy(person -> person.getAge()));
System.out.println(map1);


// key是age,value是name的list
Map<Integer, List<String>> map2 = list.stream().collect(
		Collectors.groupingBy(person -> person.getAge(), Collectors.mapping(person -> person.getName(), Collectors.toList())));
System.out.println(map2);

// key是age,value是list, 且是有序的
Map<Integer, List<Person>> map3 = list.stream().collect(
		Collectors.groupingBy(Person::getAge, () -> new LinkedHashMap<>(), Collectors.toList()));
System.out.println(map3);

// key是age,value是name的list, 且是有序的
Map<Integer, List<String>> map4 = list.stream().collect(
		Collectors.groupingBy(Person::getAge, LinkedHashMap::new, Collectors.mapping(Person::getName, Collectors.toList())));
System.out.println(map4);

// 結果 
{21=[Person(name=張三, age=21), Person(name=張四, age=21)], 23=[Person(name=趙三, age=23), Person(name=趙四, age=23)], 28=[Person(name=李三, age=28), Person(name=李四, age=28)]}
{21=[張三, 張四], 23=[趙三, 趙四], 28=[李三, 李四]}
{21=[Person(name=張三, age=21), Person(name=張四, age=21)], 28=[Person(name=李三, age=28), Person(name=李四, age=28)], 23=[Person(name=趙三, age=23), Person(name=趙四, age=23)]}
{21=[張三, 張四], 28=[李三, 李四], 23=[趙三, 趙四]}

總結

以上是生活随笔為你收集整理的Java -- Stream流用法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。