JDK8中stream常用方法操作大全
前言
JDK 1.8 引入的 Stream API 是 Java 函數(shù)式編程的核心特性之一,它提供了一種高效、聲明式的方式來處理集合數(shù)據(jù)(如 List、Set 等),支持鏈?zhǔn)讲僮?、并行處理和惰性求值?/p>
什么是 Stream?
- Stream 不是數(shù)據(jù)結(jié)構(gòu),不存儲(chǔ)元素,而是對(duì)數(shù)據(jù)源(如集合、數(shù)組)進(jìn)行計(jì)算的一系列操作(操作數(shù)據(jù)的管道)。
- 不可變:不會(huì)修改原始數(shù)據(jù)源。
- 惰性求值(Lazy Evaluation):中間操作(如 filter、map)不會(huì)立即執(zhí)行,只有遇到終端操作(如 collect、forEach)才會(huì)觸發(fā)整個(gè)流水線。
- 可并行處理(ParallelStream):提高大數(shù)據(jù)處理效率

Stream API 的基本概念
數(shù)據(jù)源:可以是任何實(shí)現(xiàn)了 Collection 接口的數(shù)據(jù)結(jié)構(gòu),或者是數(shù)組、迭代器等。
中間操作:一系列按需惰性處理數(shù)據(jù)的管道操作,如過濾、映射、排序等。
終止操作:執(zhí)行計(jì)算并返回結(jié)果的操作,如收集、聚合等。一旦執(zhí)行了終止操作,流就會(huì)被消費(fèi)掉,不能再被重復(fù)使用。
中間操作
中間操作可以鏈接起來形成流水線,常見的中間操作有:
filter(Predicate):過濾元素
map(Function):映射轉(zhuǎn)換
flatMap(Function):扁平化映射(將流中的每個(gè)元素轉(zhuǎn)為流,再合并)
distinct():去重
sorted() / sorted(Comparator):排序
peek(Consumer):調(diào)試用,對(duì)每個(gè)元素執(zhí)行操作但不改變流
limit(long):截取前 N 個(gè)
skip(long):跳過前 N 個(gè)
public static void main(String[] args) {
List<String> list = Arrays.asList("apple", "banana", "orange", "avocado","apple");
// 過濾
List<String> list1 = list.stream()
.filter(s -> s.startsWith("a"))
.filter(s -> s.length() > 5).collect(Collectors.toList());
System.out.println(list1);//[avocado]
// 映射
// 將字符串映射為對(duì)應(yīng)的長度
List<Integer> list2 = list.stream().map(String::length).collect(Collectors.toList());
System.out.println(list2);//[5, 6, 6, 7, 5]
// 將字符串映射為大寫
List<String> list3 = list.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println(list3);//[APPLE, BANANA, ORANGE, AVOCADO, APPLE]
// 映射為指定字符串
List<String> list4 = list.stream().map(item->item+"z").collect(Collectors.toList());
System.out.println(list4);//[applez, bananaz, orangez, avocadoz, applez]
// 去重
List<String> list5 = list.stream().distinct().collect(Collectors.toList());
System.out.println(list5);//[apple, banana, orange, avocado]
// 排序
List<String> list6 = list.stream().sorted().collect(Collectors.toList());
System.out.println(list6);//[apple, apple, avocado, banana, orange]
List<String> list7 = list.stream()
.sorted((s1, s2) -> s2.compareTo(s1)).collect(Collectors.toList());
System.out.println(list7);//[orange, banana, avocado, apple, apple]
// 限制和跳過
// 取前3個(gè)
List<String> list8 = list.stream()
.limit(3).collect(Collectors.toList());
System.out.println(list8);//[apple, banana, orange]
// 跳過第1個(gè)
List<String> list9 = list.stream()
.skip(1).collect(Collectors.toList());
System.out.println(list9);//[banana, orange, avocado, apple]
}終止操作
終止操作會(huì)觸發(fā)流的執(zhí)行,并且返回結(jié)果。常見的終止操作包括:
forEach(Consumer):遍歷
collect(Collector):聚合成集合、字符串等(最常用)
reduce(BinaryOperator):歸約(如求和、拼接)
count():元素個(gè)數(shù)
min() / max(Comparator):最值
anyMatch(Predicate) / allMatch / noneMatch:匹配檢查
findFirst() / findAny():查找元素(Optional)
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c", "a");
// 遍歷
list.stream().forEach(System.out::println);
// 轉(zhuǎn)換為數(shù)組
String[] array = list.stream().toArray(String[]::new);
System.out.println(array);//["a", "b", "c", "a"]
// 聚合操作
Optional<String> first = list.stream().findFirst();
System.out.println(first.get());//a
// 檢查列表中是否存在以字母"a"開頭的字符串
boolean anyMatch = list.stream().anyMatch(s -> s.startsWith("a"));
System.out.println(anyMatch);//true
// 檢查列表中所有字符串的長度是否都等于1
boolean allMatch = list.stream().allMatch(s -> s.length() == 1);
System.out.println(allMatch);//true
// 檢查列表中是否沒有任何空字符串
boolean noneMatch = list.stream().noneMatch(s -> s.isEmpty());
System.out.println(noneMatch);//true
// 計(jì)數(shù)
long count = list.stream().count();
System.out.println(count);//4
List<Integer> list2 = Arrays.asList(4,5,6,7);
// 最值
// 獲取最大值
Integer max = list2.stream().max(Integer::compareTo).orElse(0);
System.out.println("最大值: " + max);//最大值: 7
int max2 = list2.stream().mapToInt(Integer::intValue).max().orElse(0);
System.out.println("最大值: " + max2);//最大值: 7
// 獲取最小值
Integer min = list2.stream().min(Integer::compareTo).orElse(0);
System.out.println("最小值: " + min);//最小值: 4
int min2 = list2.stream().mapToInt(Integer::intValue).min().orElse(0);
System.out.println("最小值: " + min2);//最小值: 4
// 平均值
double avg = list2.stream().mapToInt(Integer::intValue).average().orElse(0.0);
System.out.println("平均數(shù): " + avg);//平均數(shù): 5.5
//求和
int sum = list2.stream().mapToInt(Integer::intValue).sum();
System.out.println("累計(jì)總和: " + sum);//累計(jì)總和: 22
// 或者使用reduce方法計(jì)算總和
Integer sum2 = list2.stream().reduce(Integer::sum).orElse(0);
System.out.println("使用reduce計(jì)算總和: " + sum2);//使用reduce計(jì)算總和: 22
//orElse()方法,主要作用是提供默認(rèn)值。
List<Integer> list3 = new ArrayList<>();
Integer max3 = list3.stream().max(Integer::compareTo).orElse(999);
System.out.println("最大值: " + max3);//最大值: 999
IntSummaryStatistics stats = list2.stream()
.collect(Collectors.summarizingInt(Integer::intValue));
System.out.println("計(jì)數(shù): " + stats.getCount()); // 計(jì)數(shù): 4
System.out.println("總和: " + stats.getSum()); // 總和: 22
System.out.println("平均值: " + stats.getAverage()); // 平均值: 5.5
System.out.println("最大值: " + stats.getMax()); // 最大值: 7
System.out.println("最小值: " + stats.getMin()); // 最小值: 4
}集合元素為類的處理
public static void main(String[] args) {
List<Person> person = Arrays.asList(
new Person("John", 25, "北京"),
new Person("Jane", 30, "深圳"),
new Person("Bob", 30, "上海"),
new Person("Mike", 20, "深圳"),
new Person("Lucy", 20, "深圳")
);
//toMap
Map<String, Person> personMap = person.stream().collect(Collectors.toMap(Person::getName, item -> item));
System.out.println(JSON.toJSONString(personMap));//{"Mike":{"age":20,"city":"深圳","name":"Mike"},"Bob":{"age":30,"city":"上海","name":"Bob"},"John":{"age":25,"city":"北京","name":"John"},"Lucy":{"age":20,"city":"深圳","name":"Lucy"},"Jane":{"age":30,"city":"深圳","name":"Jane"}}
//處理key值沖突,當(dāng)有沖突時(shí)保留上一個(gè)
Map<Integer, Person> personMap2 = person.stream().collect(Collectors.toMap(Person::getAge, item -> item, (k1, k2) -> k1));
System.out.println(JSON.toJSONString(personMap2));//{20:{"age":20,"city":"深圳","name":"Mike"},25:{"age":25,"city":"北京","name":"John"},30:{"age":30,"city":"深圳","name":"Jane"}}
//分組
Map<String, List<Person>> groupingMap = person.stream()
.collect(Collectors.groupingBy(Person::getCity));
System.out.println(JSON.toJSONString(groupingMap));//{"上海":[{"age":30,"city":"上海","name":"Bob"}],"深圳":[{"age":30,"city":"深圳","name":"Jane"},{"age":20,"city":"深圳","name":"Mike"},{"age":20,"city":"深圳","name":"Lucy"}],"北京":[{"age":25,"city":"北京","name":"John"}]}
// 多級(jí)分組
Map<String, Map<Integer, List<Person>>> multiGroupingMap = person.stream()
.collect(Collectors.groupingBy(
Person::getCity,
Collectors.groupingBy(Person::getAge)
));
System.out.println(JSON.toJSONString(multiGroupingMap));//{"上海":{30:[{"age":30,"city":"上海","name":"Bob"}]},"深圳":{20:[{"age":20,"city":"深圳","name":"Mike"},{"age":20,"city":"深圳","name":"Lucy"}],30:[{"age":30,"city":"深圳","name":"Jane"}]},"北京":{25:[{"age":25,"city":"北京","name":"John"}]}}
// 分區(qū)(分成true/false兩組)
Map<Boolean, List<Person>> partition = person.stream()
.collect(Collectors.partitioningBy(p -> p.getAge() > 25));
System.out.println(JSON.toJSONString(partition));//{false:[{"age":25,"city":"北京","name":"John"},{"age":20,"city":"深圳","name":"Mike"},{"age":20,"city":"深圳","name":"Lucy"}],true:[{"age":30,"city":"深圳","name":"Jane"},{"age":30,"city":"上海","name":"Bob"}]}
}
// 靜態(tài)內(nèi)部類
static class Person {
private String name;
private Integer age;
private String city;
public Person(String name, Integer age, String city) {
this.name = name;
this.age = age;
this.city = city;
}
public String getName() { return name; }
public Integer getAge() { return age; }
public String getCity() { return city; }
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", city='" + city + '\'' +
'}';
}
}并行流
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
for (int i = 0; i < 50000; i++) {
int j = i % 30;
Person person = new Person("用戶"+i, j, "test"+i);
list.add(person);
}
long startTime = System.currentTimeMillis();
List<Person> test1 = list.stream().filter(item -> item.getAge() > 20).map(item -> {
item.setAge(item.getAge() * 2);
return item;
}).collect(Collectors.toList());
long endTime = System.currentTimeMillis();
System.out.println("執(zhí)行時(shí)間: " + (endTime - startTime) + " 毫秒");//執(zhí)行時(shí)間: 63 毫秒
long startTime2 = System.currentTimeMillis();
List<Person> test2 = list.parallelStream().filter(item -> item.getAge() > 20).map(item -> {
item.setAge(item.getAge() * 2);
return item;
}).collect(Collectors.toList());
long endTime2 = System.currentTimeMillis();
System.out.println("執(zhí)行時(shí)間: " + (endTime2 - startTime2) + " 毫秒");//執(zhí)行時(shí)間: 19 毫秒
}
// 靜態(tài)內(nèi)部類
static class Person {
private String name;
private Integer age;
private String city;
public Person(String name, Integer age, String city) {
this.name = name;
this.age = age;
this.city = city;
}
public String getName() { return name; }
public Integer getAge() { return age; }
public String getCity() { return city; }
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", city='" + city + '\'' +
'}';
}
}到此這篇關(guān)于JDK8中stream中常用方法的文章就介紹到這了,更多相關(guān)jdk8 stream方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring啟動(dòng)過程中實(shí)例化部分代碼的分析之Bean的推斷構(gòu)造方法
這篇文章主要介紹了Spring啟動(dòng)過程中實(shí)例化部分代碼的分析之Bean的推斷構(gòu)造方法,實(shí)例化這一步便是在doCreateBean方法的?instanceWrapper?=?createBeanInstance(beanName,?mbd,?args);這段代碼中,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-09-09
SpringSecurity拋出異常但AccessDeniedHandler不生效的解決
本文主要介紹了SpringSecurity拋出異常但AccessDeniedHandler不生效的解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01
springboot+mybatis-plus基于攔截器實(shí)現(xiàn)分表的示例代碼
本文主要介紹了springboot+mybatis-plus基于攔截器實(shí)現(xiàn)分表,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
Spring Batch輕量級(jí)批處理框架實(shí)戰(zhàn)
本文主要介紹了Spring Batch輕量級(jí)批處理框架實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
淺談Java內(nèi)存模型之happens-before
于存在線程本地內(nèi)存和主內(nèi)存的原因,再加上重排序,會(huì)導(dǎo)致多線程環(huán)境下存在可見性的問題。那么我們正確使用同步、鎖的情況下,線程A修改了變量a何時(shí)對(duì)線程B可見?下面小編來簡單介紹下2019-05-05
springboot新建項(xiàng)目pom.xml文件第一行報(bào)錯(cuò)的解決
這篇文章主要介紹了springboot新建項(xiàng)目pom.xml文件第一行報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01

