Stream
將要處理的元素集合看作一種流崎岂,在流的過程中捆毫,借助Stream API
對流中的元素進(jìn)行操作,比如:篩選冲甘、排序冻璃、聚合等响谓。
Stream
的操作符大體上分為兩種:中間操作符
和終止操作符
中間操作符
對于數(shù)據(jù)流來說,中間操作符在執(zhí)行制定處理程序后省艳,數(shù)據(jù)流依然可以傳遞給下一級的操作符娘纷。
中間操作符包含8種(排除了parallel,sequential,這兩個(gè)操作并不涉及到對數(shù)據(jù)流的加工操作):
- map(mapToInt,mapToLong,mapToDouble) 轉(zhuǎn)換操作符跋炕,把比如A->B赖晶,這里默認(rèn)提供了轉(zhuǎn)int,long辐烂,double的操作符遏插。
- flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把 int[]{2,3,4} 拍平 變成 2,3纠修,4 也就是從原來的一個(gè)數(shù)據(jù)變成了3個(gè)數(shù)據(jù)胳嘲,這里默認(rèn)提供了拍平成int,long,double的操作符。
- limit 限流操作扣草,比如數(shù)據(jù)流中有10個(gè) 我只要出前3個(gè)就可以使用了牛。
- distint 去重操作,對重復(fù)元素去重辰妙,底層使用了equals方法鹰祸。
- filter 過濾操作,把不想要的數(shù)據(jù)過濾密浑。
- peek 挑出操作蛙婴,如果想對數(shù)據(jù)進(jìn)行某些操作,如:讀取尔破、編輯修改等街图。
- skip 跳過操作,跳過某些元素懒构。
- sorted(unordered) 排序操作台夺,對元素排序,前提是實(shí)現(xiàn)Comparable接口痴脾,當(dāng)然也可以自定義比較器颤介。
終止操作符
數(shù)據(jù)經(jīng)過中間加工操作,就輪到終止操作符上場了赞赖;
終止操作符就是用來對數(shù)據(jù)進(jìn)行收集或者消費(fèi)的滚朵,數(shù)據(jù)到了終止操作這里就不會(huì)向下流動(dòng)了,終止操作符只能使用一次前域。
- collect 收集操作辕近,將所有數(shù)據(jù)收集起來,這個(gè)操作非常重要匿垄,官方的提供的Collectors 提供了非常多收集器移宅,可以說Stream 的核心在于Collectors归粉。
- count 統(tǒng)計(jì)操作,統(tǒng)計(jì)最終的數(shù)據(jù)個(gè)數(shù)漏峰。
- findFirst糠悼、findAny 查找操作,查找第一個(gè)浅乔、查找任何一個(gè) 返回的類型為Optional倔喂。
- noneMatch、allMatch靖苇、anyMatch 匹配操作席噩,數(shù)據(jù)流中是否存在符合條件的元素 返回值為bool 值。
- min贤壁、max 最值操作悼枢,需要自定義比較器,返回?cái)?shù)據(jù)流中最大最小的值脾拆。
- reduce 規(guī)約操作馒索,將整個(gè)數(shù)據(jù)流的值規(guī)約為一個(gè)值,count假丧、min双揪、max底層就是使用reduce动羽。
- forEach包帚、forEachOrdered 遍歷操作,這里就是對最終的數(shù)據(jù)進(jìn)行消費(fèi)了运吓。
- toArray 數(shù)組操作渴邦,將數(shù)據(jù)流的元素轉(zhuǎn)換成數(shù)組。
Stream的創(chuàng)建
1拘哨、通過 java.util.Collection.stream()
方法用集合創(chuàng)建流
List<String> list = Arrays.asList("a", "b", "c");
// 創(chuàng)建一個(gè)順序流
Stream<String> stream = list.stream();
// 創(chuàng)建一個(gè)并行流
Stream<String> parallelStream = list.parallelStream();
2谋梭、使用java.util.Arrays.stream(T[] array)
方法用數(shù)組創(chuàng)建流
int[] array={1,3,5,6,8};
IntStream stream = Arrays.stream(array);
3、使用Stream
的靜態(tài)方法:of()倦青、iterate()瓮床、generate()
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println); // 0 3 6 9
Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);
輸出結(jié)果:
3
6
9
0.8106623442686114
0.11554643727388458
0.1404645961428974
Process finished with exit code 0
stream
和parallelStream
的簡單區(qū)分:
stream
是順序流,由主線程按順序?qū)α鲌?zhí)行操作产镐;
parallelStream
是并行流隘庄,內(nèi)部以多線程并行執(zhí)行的方式對流進(jìn)行操作,但前提是流中的數(shù)據(jù)處理沒有順序要求癣亚。
例如篩選集合中的奇數(shù)丑掺,兩者的處理不同之處:
Stream使用
遍歷/匹配(foreach/find/match)
Stream
也是支持類似集合的遍歷和匹配元素的,只是Stream
中的元素是以Optional
類型存在的述雾。Stream
的遍歷街州、匹配非常簡單兼丰。
public class StreamTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
// 遍歷輸出符合條件的元素
list.stream().filter(x -> x > 6).forEach(System.out::println);
// 匹配第一個(gè)
Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
// 匹配任意(適用于并行流)
Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
// 是否包含符合特定條件的元素
boolean anyMatch = list.stream().anyMatch(x -> x < 6);
System.out.println("匹配第一個(gè)值:" + findFirst.get());
System.out.println("匹配任意一個(gè)值:" + findAny.get());
System.out.println("是否存在大于6的值:" + anyMatch);
}
}
輸出結(jié)果:
7
9
8
匹配第一個(gè)值:7
匹配任意一個(gè)值:8
是否存在大于6的值:true
Process finished with exit code 0
篩選(filter)
篩選,是按照一定的規(guī)則校驗(yàn)流中的元素唆缴,將符合條件的元素提取到新的流中的操作鳍征。
篩選出Integer
集合中大于7的元素,并打印出來
public class StreamTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(6, 7, 3, 8, 1, 2, 9);
Stream<Integer> stream = list.stream();
stream.filter(x -> x > 7).forEach(System.out::println);
}
}
輸出結(jié)果:
8
9
Process finished with exit code 0
聚合(max/min/count)
max
琐谤、min
蟆技、count
這些字眼你一定不陌生,沒錯(cuò)斗忌,在mysql中我們常用它們進(jìn)行數(shù)據(jù)統(tǒng)計(jì)质礼。Java stream中也引入了這些概念和用法,極大地方便了我們對集合织阳、數(shù)組的數(shù)據(jù)統(tǒng)計(jì)工作眶蕉。
案例一:獲取String
集合中最長的元素。
public class StreamTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd");
Optional<String> max = list.stream().max(Comparator.comparing(String::length));
System.out.println("最長的字符串:" + max.get());
}
}
輸出結(jié)果:
最長的字符串:weoujgsd
Process finished with exit code 0
案例二:獲取Integer
集合中的最大值唧躲。
public class StreamTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(7, 6, 9, 4, 11, 6);
// 自然排序
Optional<Integer> max = list.stream().max(Integer::compareTo);
// 自定義排序
Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
System.out.println("自然排序的最大值:" + max.get());
System.out.println("自定義排序的最大值:" + max2.get());
}
}
輸出結(jié)果:
自然排序的最大值:11
自定義排序的最大值:11
Process finished with exit code 0
案例三:計(jì)算Integer
集合中大于6的元素的個(gè)數(shù)造挽。
public class StreamTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(7, 6, 4, 8, 2, 11, 9);
long count = list.stream().filter(x -> x > 6).count();
System.out.println("list中大于6的元素個(gè)數(shù):" + count);
}
}
輸出結(jié)果:
list中大于6的元素個(gè)數(shù):4
Process finished with exit code 0
映射(map/flatMap)
映射,可以將一個(gè)流的元素按照一定的映射規(guī)則映射到另一個(gè)流中弄痹。分為map
和flatMap
:
-
map
:接收一個(gè)函數(shù)作為參數(shù)饭入,該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上,并將其映射成一個(gè)新的元素肛真。 -
flatMap
:接收一個(gè)函數(shù)作為參數(shù)谐丢,將流中的每個(gè)值都換成另一個(gè)流,然后把所有流連接成一個(gè)流蚓让。
案例一:英文字符串?dāng)?shù)組的元素全部改為大寫乾忱。整數(shù)數(shù)組每個(gè)元素+3。
public class StreamTest {
public static void main(String[] args) {
String[] strArr = { "abcd", "bcdd", "defde", "fTr" };
List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList());
System.out.println("每個(gè)元素大寫:" + strList);
List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);
List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList());
System.out.println("每個(gè)元素+3:" + intListNew);
}
}
輸出結(jié)果:
每個(gè)元素大寫:[ABCD, BCDD, DEFDE, FTR]
每個(gè)元素+3:[4, 6, 8, 10, 12, 14]
Process finished with exit code 0
案例二:將兩個(gè)字符數(shù)組合并成一個(gè)新的字符數(shù)組历极。
public class StreamTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7");
List<String> listNew = list.stream().flatMap(s -> {
// 將每個(gè)元素轉(zhuǎn)換成一個(gè)stream
String[] split = s.split(",");
Stream<String> s2 = Arrays.stream(split);
return s2;
}).collect(Collectors.toList());
System.out.println("處理前的集合:" + list);
System.out.println("處理后的集合:" + listNew);
}
}
輸出結(jié)果:
處理前的集合:[m,k,l,a, 1,3,5,7]
處理后的集合:[m, k, l, a, 1, 3, 5, 7]
Process finished with exit code 0
歸約(reduce)
歸約窄瘟,也稱縮減,顧名思義趟卸,是把一個(gè)流縮減成一個(gè)值蹄葱,能實(shí)現(xiàn)對集合求和、求乘積和求最值操作锄列。
案例一:求Integer
集合的元素之和图云、乘積和最大值。
public class StreamTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
// 求和方式1
Optional<Integer> sum = list.stream().reduce(Integer::sum);
// 求和方式2
Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
// 求和方式3
Integer sum3 = list.stream().reduce(0, Integer::sum);
// 求乘積
Optional<Integer> product = list.stream().reduce((x, y) -> x * y);
// 求最大值方式1
Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
// 求最大值寫法2
Integer max2 = list.stream().reduce(1, Integer::max);
System.out.println("list求和:" + sum.get() + "," + sum2.get() + "," + sum3);
System.out.println("list求積:" + product.get());
System.out.println("list求和:" + max.get() + "," + max2);
}
}
輸出結(jié)果:
list求和:29,29,29
list求積:2112
list求和:11,11
Process finished with exit code 0
歸集(toList/toSet/toMap)
因?yàn)榱鞑淮鎯?chǔ)數(shù)據(jù)右蕊,那么在流中的數(shù)據(jù)完成處理后琼稻,需要將流中的數(shù)據(jù)重新歸集到新的集合里。toList
饶囚、toSet
和toMap
比較常用帕翻,另外還有toCollection
鸠补、toConcurrentMap
等復(fù)雜一些的用法。
下面用一個(gè)案例演示toList
嘀掸、toSet
和toMap
:
public class Person {
private String name; // 姓名
private int salary; // 薪資
private int age; // 年齡
private String sex; //性別
private String area; // 地區(qū)
// 構(gòu)造方法
public Person(String name, int salary, int age,String sex,String area) {
this.name = name;
this.salary = salary;
this.age = age;
this.sex = sex;
this.area = area;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", salary=" + salary +
", age=" + age +
", sex='" + sex + '\'' +
", area='" + area + '\'' +
'}';
}
}
public class StreamTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
personList.add(new Person("Anni", 8200, 24, "female", "New York"));
Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
.collect(Collectors.toMap(Person::getName, p -> p));
System.out.println("toList:" + listNew);
System.out.println("toSet:" + set);
System.out.println("toMap:" + map);
}
}
輸出結(jié)果:
toList:[6, 4, 6, 6, 20]
toSet:[4, 20, 6]
toMap:{Tom=Person{name='Tom', salary=8900, age=23, sex='male', area='New York'}, Anni=Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}}
Process finished with exit code 0
統(tǒng)計(jì)(count/averaging)
Collectors
提供了一系列用于數(shù)據(jù)統(tǒng)計(jì)的靜態(tài)方法:
- 計(jì)數(shù):
count
- 平均值:
averagingInt
紫岩、averagingLong
、averagingDouble
- 最值:
maxBy
睬塌、minBy
- 求和:
summingInt
泉蝌、summingLong
、summingDouble
- 統(tǒng)計(jì)以上所有:
summarizingInt
揩晴、summarizingLong
勋陪、summarizingDouble
案例:統(tǒng)計(jì)員工人數(shù)、平均工資硫兰、工資總額诅愚、最高工資。
public class StreamTest {
public static void main(String[] args) {
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
// 求總數(shù)
long count = personList.size();
// 求平均工資
Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
// 求最高工資
Optional<Integer> max = personList.stream().map(Person::getSalary).max(Integer::compare);
// 求工資之和
int sum = personList.stream().mapToInt(Person::getSalary).sum();
// 一次性統(tǒng)計(jì)所有信息
DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
System.out.println("員工總數(shù):" + count);
System.out.println("員工平均工資:" + average);
System.out.println("員工最高工資:" + max.get());
System.out.println("員工工資總和:" + sum);
System.out.println("員工工資所有統(tǒng)計(jì):" + collect);
}
}
輸出結(jié)果:
員工總數(shù):3
員工平均工資:7900.0
員工最高工資:8900
員工工資總和:23700
員工工資所有統(tǒng)計(jì):DoubleSummaryStatistics{count=3, sum=23700.000000, min=7000.000000, average=7900.000000, max=8900.000000}
Process finished with exit code 0
分組(partitioningBy/groupingBy)
- 分區(qū):將
stream
按條件分為兩個(gè)Map
劫映,比如員工按薪資是否高于8000分為兩部分违孝。 - 分組:將集合分為多個(gè)Map,比如員工按性別分組泳赋。有單級分組和多級分組雌桑。
案例:將員工按薪資是否高于8000分為兩部分;將員工按性別和地區(qū)分組
public class StreamTest {
public static void main(String[] args) {
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "Washington"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "New York"));
personList.add(new Person("Anni", 8200, 24, "female", "New York"));
// 將員工按薪資是否高于8000分組
Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
// 將員工按性別分組
Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
// 將員工先按性別分組祖今,再按地區(qū)分組
Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
System.out.println("員工按薪資是否大于8000分組情況:" + part);
System.out.println("員工按性別分組情況:" + group);
System.out.println("員工按性別校坑、地區(qū):" + group2);
}
}
輸出結(jié)果:
員工按薪資是否大于8000分組情況:{false=[Person{name='Jack', salary=7000, age=25, sex='male', area='Washington'}, Person{name='Lily', salary=7800, age=21, sex='female', area='New York'}], true=[Person{name='Tom', salary=8900, age=23, sex='male', area='Washington'}, Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}]}
員工按性別分組情況:{female=[Person{name='Lily', salary=7800, age=21, sex='female', area='New York'}, Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}], male=[Person{name='Tom', salary=8900, age=23, sex='male', area='Washington'}, Person{name='Jack', salary=7000, age=25, sex='male', area='Washington'}]}
員工按性別、地區(qū):{female={New York=[Person{name='Lily', salary=7800, age=21, sex='female', area='New York'}, Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}]}, male={Washington=[Person{name='Tom', salary=8900, age=23, sex='male', area='Washington'}, Person{name='Jack', salary=7000, age=25, sex='male', area='Washington'}]}}
Process finished with exit code 0
接合(joining)
joining
可以將stream中的元素用特定的連接符(沒有的話衅鹿,則直接連接)連接成一個(gè)字符串撒踪。
public class StreamTest {
public static void main(String[] args) {
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
String names = personList.stream().map(Person::getName).collect(Collectors.joining(","));
System.out.println("所有員工的姓名:" + names);
List<String> list = Arrays.asList("A", "B", "C");
String string = list.stream().collect(Collectors.joining("-"));
System.out.println("拼接后的字符串:" + string);
}
}
輸出結(jié)果:
所有員工的姓名:Tom,Jack,Lily
拼接后的字符串:A-B-C
Process finished with exit code 0
排序(sorted)
sorted
过咬,中間操作大渤。有兩種排序:
-
sorted()
:自然排序,流中元素需實(shí)現(xiàn)Comparable
接口 -
sorted(Comparator com)
:Comparator
排序器自定義排序
案例:將員工按工資由高到低(工資一樣則按年齡由大到械Ы省)排序
public class StreamTest {
public static void main(String[] args) {
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Sherry", 9000, 24, "female", "New York"));
personList.add(new Person("Tom", 8900, 22, "male", "Washington"));
personList.add(new Person("Jack", 9000, 25, "male", "Washington"));
personList.add(new Person("Lily", 8800, 26, "male", "New York"));
personList.add(new Person("Alisa", 9000, 26, "female", "New York"));
// 按工資升序排序(自然排序)
List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)
.collect(Collectors.toList());
// 按工資倒序排序
List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
.map(Person::getName).collect(Collectors.toList());
// 先按工資再按年齡升序排序
List<String> newList3 = personList.stream()
.sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
.collect(Collectors.toList());
// 先按工資再按年齡自定義排序(降序)
List<String> newList4 = personList.stream().sorted((p1, p2) -> {
if (p1.getSalary() == p2.getSalary()) {
return p2.getAge() - p1.getAge();
} else {
return p2.getSalary() - p1.getSalary();
}
}).map(Person::getName).collect(Collectors.toList());
System.out.println("按工資升序排序:" + newList);
System.out.println("按工資降序排序:" + newList2);
System.out.println("先按工資再按年齡升序排序:" + newList3);
System.out.println("先按工資再按年齡自定義降序排序:" + newList4);
}
}
輸出結(jié)果:
按工資升序排序:[Lily, Tom, Sherry, Jack, Alisa]
按工資降序排序:[Sherry, Jack, Alisa, Tom, Lily]
先按工資再按年齡升序排序:[Lily, Tom, Sherry, Jack, Alisa]
先按工資再按年齡自定義降序排序:[Alisa, Jack, Sherry, Tom, Lily]
Process finished with exit code 0
提取/組合
流也可以進(jìn)行合并泵三、去重、限制衔掸、跳過等操作烫幕。
public class StreamTest {
public static void main(String[] args) {
String[] arr1 = { "a", "b", "c", "d" };
String[] arr2 = { "d", "e", "f", "g" };
Stream<String> stream1 = Stream.of(arr1);
Stream<String> stream2 = Stream.of(arr2);
// concat:合并兩個(gè)流 distinct:去重
List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
// limit:限制從流中獲得前n個(gè)數(shù)據(jù)
List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
// skip:跳過前n個(gè)數(shù)據(jù)
List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
System.out.println("流合并:" + newList);
System.out.println("limit:" + collect);
System.out.println("skip:" + collect2);
}
}
輸出結(jié)果:
流合并:[a, b, c, d, e, f, g]
limit:[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
skip:[3, 5, 7, 9, 11]
Process finished with exit code 0
分頁操作
stream api 的強(qiáng)大之處還不僅僅是對集合進(jìn)行各種組合操作,還支持分頁操作敞映。
例如较曼,將如下的數(shù)組從小到大進(jìn)行排序,排序完成之后振愿,從第1行開始捷犹,查詢10條數(shù)據(jù)出來弛饭,操作如下:
//需要查詢的數(shù)據(jù)
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5, 10, 6, 20, 30, 40, 50, 60, 100);
List<Integer> dataList = numbers.stream().sorted(Integer::compareTo).skip(0).limit(10).collect(Collectors.toList());
System.out.println(dataList.toString());
輸出結(jié)果:
[2, 2, 3, 3, 3, 5, 6, 7, 10, 20]
Process finished with exit code 0
并行操作
所謂并行,指的是多個(gè)任務(wù)在同一時(shí)間點(diǎn)發(fā)生萍歉,并由不同的cpu進(jìn)行處理侣颂,不互相搶占資源;而并發(fā)枪孩,指的是多個(gè)任務(wù)在同一時(shí)間點(diǎn)內(nèi)同時(shí)發(fā)生了憔晒,但由同一個(gè)cpu進(jìn)行處理,互相搶占資源蔑舞。
stream api 的并行操作和串行操作拒担,只有一個(gè)方法區(qū)別,其他都一樣攻询,例如下面我們使用parallelStream來輸出空字符串的數(shù)量:
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
// 采用并行計(jì)算方法澎蛛,獲取空字符串的數(shù)量
long count = strings.parallelStream().filter(String::isEmpty).count();
System.out.println(count);
在實(shí)際使用的時(shí)候,并行操作
不一定比串行操作
快蜕窿!對于簡單操作谋逻,數(shù)量非常大,同時(shí)服務(wù)器是多核的話桐经,建議使用Stream并行毁兆!反之,采用串行操作更可靠阴挣!
集合轉(zhuǎn)Map操作
在實(shí)際的開發(fā)過程中气堕,還有一個(gè)使用最頻繁的操作就是,將集合元素中某個(gè)主鍵字段作為key畔咧,元素作為value茎芭,來實(shí)現(xiàn)集合轉(zhuǎn)map的需求,這種需求在數(shù)據(jù)組裝方面使用的非常多誓沸。
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("Tom",7000,25,"male","安徽"));
personList.add(new Person("Jack",8000,30,"female","北京"));
personList.add(new Person("Lucy",9000,40,"male","上海"));
personList.add(new Person("Airs",10000,40,"female","深圳"));
Map<Integer, Person> collect = personList.stream().collect(Collectors.toMap(Person::getAge, v -> v, (k1, k2) -> k1));
System.out.println(collect);
}
輸出結(jié)果:
{40=Person{name='Lucy', salary=9000, age=40, sex='male', area='上海'}, 25=Person{name='Tom', salary=7000, age=25, sex='male', area='安徽'}, 30=Person{name='Jack', salary=8000, age=30, sex='female', area='北京'}}
Process finished with exit code 0
打開Collectors.toMap
方法源碼梅桩,一起來看看。
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
從參數(shù)表可以看出:
- 第一個(gè)參數(shù):表示 key
- 第二個(gè)參數(shù):表示 value
- 第三個(gè)參數(shù):表示某種規(guī)則
上文中的Collectors.toMap(Person::getAge, v -> v, (k1,k2) -> k1)
拜隧,表達(dá)的意思就是將age
的內(nèi)容作為key
宿百,v -> v
是表示將元素person
作為value
,其中(k1,k2) -> k1
表示如果存在相同的key
洪添,將第一個(gè)匹配的元素作為內(nèi)容垦页,第二個(gè)舍棄!
標(biāo)簽: [Java]