java8關(guān)于stream操作api總結(jié):
一岗喉、先介紹幾個(gè)名詞:
1坯癣、中間操作:
中間操作會(huì)產(chǎn)生另一個(gè)流哼勇。因此中間操作可以用來(lái)創(chuàng)建執(zhí)行一系列動(dòng)作的管道都伪。一個(gè)特別需要注意的點(diǎn)是:中間操作不是立即發(fā)生的。相反积担,當(dāng)在中間操作創(chuàng)建的新流上執(zhí)行完終端操作后陨晶,中間操作指定的操作才會(huì)發(fā)生
2、終止操作:
會(huì)消費(fèi)流帝璧,這種操作會(huì)產(chǎn)生一個(gè)結(jié)果的先誉,如果一個(gè)流被消費(fèi)過(guò)了湿刽,那它就不能被重用的。
3褐耳、"中間操作"的狀態(tài):
(1)無(wú)狀態(tài)操作:在處理流中的每個(gè)元素時(shí)诈闺,與其他元素?zé)o關(guān)
(2)有狀態(tài)操作:在處理流中的每個(gè)元素時(shí),依賴其他元素(eg:min铃芦,max之類的)
4雅镊、縮減操作:
把一個(gè)流經(jīng)過(guò)一個(gè)操作,輸出一個(gè)值杨帽。eg:min、max嗤军,或者典型的reduce操作
5注盈、for&forEach:
我們?cè)谠L問(wèn)一個(gè)數(shù)組元素的時(shí)候,最快的方式肯定是通過(guò)索引去訪問(wèn)的吧叙赚,而for循環(huán)遍歷的時(shí)候就是通過(guò)下標(biāo)進(jìn)行的老客,所以效率那是相當(dāng)?shù)母撸钱?dāng)我們的數(shù)據(jù)結(jié)構(gòu)不是數(shù)組的時(shí)候震叮,比如是鏈表的時(shí)候胧砰,可想而知,for循環(huán)的效率是有多低苇瓣,但是forEach底層采用的是迭代器的方式尉间,他對(duì)數(shù)據(jù)結(jié)構(gòu)是沒(méi)有要求的,不管上層的數(shù)據(jù)結(jié)構(gòu)是什么击罪,他都能保證高效地執(zhí)行哲嘲!因此我的最終答案:如果數(shù)據(jù)結(jié)構(gòu)是ArrayList這種數(shù)據(jù)結(jié)構(gòu),那你可以采用for媳禁,但是你的數(shù)據(jù)結(jié)構(gòu)如果是LinkList那你千萬(wàn)別再用for,應(yīng)該果斷采用forEach眠副。
6、并行流:
調(diào)用parallel()就可以獲取到一個(gè)并行流了竣稽,幫助我們多線程操作囱怕,提高效。需要注意的是毫别,服務(wù)器需要多核支持
for循環(huán),stream操作,并行stream操作的性能對(duì)比:
并行stream > for > stream : 數(shù)據(jù)量不大或者核數(shù)不夠多的情況下娃弓,for比并行stream效率高
二、各種api:
1岛宦、中間操作——篩選
方法 |
描述 |
filter(Predicate p) |
接收 Lambda 忘闻, 從流中排除某些元素。 |
distinct() |
篩選恋博,通過(guò)流所生成元素的 hashCode() 和 equals() 去除重復(fù)元素 |
limit(long maxSize) |
截?cái)嗔髌爰眩蛊湓夭怀^(guò)給定數(shù)量私恬。 |
skip(long n) |
跳過(guò)元素,返回一個(gè)扔掉了前 n 個(gè)元素的流炼吴。若流中元素不足 n 個(gè)本鸣,則返回一個(gè)空流。與 limit(n) 互補(bǔ) |
2硅蹦、中間操作——映射
方法 |
描述 |
map(Function f) |
接收一個(gè)函數(shù)作為參數(shù)荣德,該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上,并將其映射成一個(gè)新的元素童芹。 |
mapToDouble(ToDoubleFunction ) |
接收一個(gè)函數(shù)作為參數(shù)涮瞻,該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上,產(chǎn)生一個(gè)新的 DoubleStream假褪。 |
mapToInt(ToIntFunction ) |
接收一個(gè)函數(shù)作為參數(shù)署咽,該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上,產(chǎn)生一個(gè)新的 IntStream生音。 |
mapToLong(ToLongFunction ) |
接收一個(gè)函數(shù)作為參數(shù)宁否,該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上,產(chǎn)生一個(gè)新的 LongStream缀遍。 |
flatMap(Function f) |
接收一個(gè)函數(shù)作為參數(shù)慕匠,將流中的每個(gè)值都換成另一個(gè)流,然后把所有流連接成一個(gè)流 |
3域醇、中間操作——排序
方法 |
描述 |
sorted() |
產(chǎn)生一個(gè)新流台谊,其中按自然順序排序 |
sorted(Comparator comp) |
產(chǎn)生一個(gè)新流,其中按比較器順序排序 |
4譬挚、終止操作——查找與匹配
方法 |
描述 |
allMatch(Predicate p) |
檢查是否匹配所有元素 |
anyMatch(Predicate ) |
檢查是否至少匹配一個(gè)元素 |
noneMatch(Predicate p) |
檢查是否沒(méi)有匹配所有元素 |
findFirst() |
返回第一個(gè)元素 |
findAny() |
返回當(dāng)前流中的任意元素 |
count() |
返回流中元素總數(shù) |
max(Comparator c) |
返回流中最大值 |
min(Comparator c) |
返回流中最小值 |
forEach(Consumer c) |
stream API 使用內(nèi)部迭代(默認(rèn)做了外部迭代) |
5青伤、終止操作——?dú)w約
方法 |
描述 |
reduce(T identity, BinaryOperator b) |
可以將流中元素反復(fù)結(jié)合起來(lái),得到一個(gè)值殴瘦。返回 T狠角。<br />在第一個(gè)版本當(dāng)中,identity是這樣一個(gè)值蚪腋,對(duì)于涉及identity和流中任意的累積操作丰歌,得到的結(jié)果就是元素自身,沒(méi)有任何改變屉凯。比如立帖,如果是加法,他就是0悠砚,如果是乘法他就是1晓勇。 |
reduce(BinaryOperator b) |
可以將流中元素反復(fù)結(jié)合起來(lái),得到一個(gè)值。返回 Optional |
@Test
public void reduceParallel() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
//每個(gè)元素都放大兩倍后绑咱,再求積
Integer product = lists.parallelStream().reduce(1, (a, b) -> a * (b * 2),
(a, b) -> a * b);
System.out.println("product:" + product);//48
Integer product2 = lists.parallelStream().reduce(1, (a, b) -> {
System.out.println("第一個(gè)參數(shù):" + Thread.currentThread().getName() +",a="+a+",b="+b);
return a * (b * 2);},
(a, b) -> {
System.out.println("第二個(gè)參數(shù):" + Thread.currentThread().getName()+",c="+a+",d="+b);
return a * b;
});
System.out.println("product2:" + product);//48
}
6绰筛、終止操作——收集,注意這里返回的都是一個(gè)收集器Collector
方法 |
描述 |
collect(Collector c) |
將流轉(zhuǎn)換為其他形式描融。接收一個(gè) Collector接口的實(shí)現(xiàn)铝噩,用于給Stream中元素做匯總的方法 |
三、關(guān)于各種收集器:
1窿克、均值——averaging
方法 |
描述 |
averagingInt(ToIntFunction<? super T> mapper) |
接收一個(gè)函數(shù)作為參數(shù)骏庸,求該函數(shù)的返回值(int)的均值 |
averagingLong(ToLongFunction<? super T> mapper) |
接收一個(gè)函數(shù)作為參數(shù),求該函數(shù)的返回值(long)的均值 |
averagingDouble(ToDoubleFunction<? super T> mapper) |
接收一個(gè)函數(shù)作為參數(shù)年叮,求該函數(shù)的返回值(double)的均值 |
@Test
public void testAveraging() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
Double average = lists.stream().collect(Collectors.averagingInt(item -> item));
System.out.println(average);
}
2具被、統(tǒng)計(jì)——元素個(gè)數(shù):counting
方法 |
描述 |
counting() |
統(tǒng)計(jì)輸入元素的個(gè)數(shù) |
@Test
public void testCounting() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
Long count = lists.stream().collect(Collectors.counting());
System.out.println(count);
}
3、最值——maxBy只损、minBy
方法 |
描述 |
minBy(Comparator<? super T> comparator) |
接收一個(gè)比較器一姿,返回最小值 |
maxBy(Comparator<? super T> comparator) |
接收一個(gè)比較器,返回最大值 |
@Test
public void testMax() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
Optional<Integer> max = lists.stream().collect(Collectors.maxBy(Integer::compare));
if (max.isPresent()){
System.out.println(max.get());
}
}
4改执、求和——summing啸蜜、summarizing
方法 |
描述 |
summingInt(ToIntFunction<? super T> mapper) |
可以計(jì)算輸入元素的總和 |
summingLong(ToLongFunction<? super T> mapper) |
可以計(jì)算輸入元素的總和 |
summingDouble(ToDoubleFunction<? super T> mapper) |
可以計(jì)算輸入元素的總和 |
summarizingInt(ToIntFunction<? super T> mapper) |
可以計(jì)算輸入元素的總和,平均值,數(shù)量,最值 |
summarizingLong(ToLongFunction<? super T> mapper) |
可以計(jì)算輸入元素的總和,平均值,數(shù)量,最值 |
summarizingDouble(ToDoubleFunction<? super T> mapper) |
可以計(jì)算輸入元素的總和,平均值,數(shù)量,最值 |
@Test
public void testSummary() {
List<Integer> lists = new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
Integer sum = lists.stream().collect(Collectors.summingInt((item) -> item));
System.out.println(sum);
IntSummaryStatistics summary = lists.stream().collect(Collectors.summarizingInt((item) -> item));
System.out.println(summary.getSum());
System.out.println(summary.getAverage());
System.out.println(summary.getCount());
System.out.println(summary.getMax());
System.out.println(summary.getMin());
}
5坑雅、分組——groupingBy,groupingByConcurrent
方法 |
描述 |
groupingBy(Function<? super T, ? extends K> classifier) |
classifier提供結(jié)果Map(HashMap)的鍵 |
groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) |
downstream提供結(jié)果Map和值 |
groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream) |
mapFactory指定結(jié)果Map的類型 |
groupingByConcurrent(Function<? super T, ? extends K> classifier) |
classifier提供結(jié)果Map(HashMap)的鍵,將元素整理成ConcurrentMap |
groupingByConcurrent(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) |
downstream提供結(jié)果Map和值,將元素整理成ConcurrentMap |
groupingByConcurrent(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory,Collector<? super T, A, D> downstream) |
mapFactory指定結(jié)果Map的類型,將元素整理成ConcurrentMap |
@Data
@Builder
static class Student{
private Long id;
private String name;
private Long classId;
private Integer age;
}
@Test
public void testGroup() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("張三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("趙六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
//根據(jù)classId分組
Map<Long, List<Student>> map1 = list.stream().collect(Collectors.groupingBy(Student::getClassId));
System.out.println("map1:\n" + map1);
//統(tǒng)計(jì)各個(gè)classId的人數(shù)
Map<Long, Long> map2 = list.stream().collect(Collectors.groupingBy(Student::getClassId,
Collectors.counting()));
System.out.println("map2:\n" + map2);
//統(tǒng)計(jì)各個(gè)classId的人數(shù)
Map<Long, Long> map3 = list.stream().collect(Collectors.groupingBy(Student::getClassId,
HashMap::new,
Collectors.counting()));
System.out.println("map3:\n" + map3);
}
6辈挂、分區(qū)——partitioningBy
方法 |
描述 |
partitioningBy(Predicate<? super T> predicate) |
該操作將輸入元素分為兩類(即鍵是true和false的Map),predicate提供分區(qū)依據(jù) |
partitioningBy(Predicate<? super T> predicate,Collector<? super T, A, D> downstream) |
該操作將輸入元素分為兩類(即鍵是true和false的Map),downstream提供結(jié)果Map的值 |
@Test
public void testPartitioning() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("張三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("趙六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
Map<Boolean, List<Student>> map = list.stream().collect(Collectors.partitioningBy((item -> item.getAge() > 20)));
System.out.println("map:\n" + map);
Map<Boolean, Long> map1 = list.stream().collect(Collectors.partitioningBy((item -> item.getAge() > 20),
Collectors.counting()));
System.out.println("map1:\n" + map1);//{false=1, true=3}
}
7、Collector之后再操作——collectingAndThen
方法 |
描述 |
collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) |
downstream(Collector類型)和finisher(Function類型)裹粤,在調(diào)用downstream之后终蒂,將調(diào)用結(jié)果值作為finisher的傳入值,再調(diào)用finisher遥诉。 |
@Test
public void testCollectingAndThen() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
String result = list.stream().collect(Collectors.collectingAndThen(Collectors.counting(),
(ret) -> "統(tǒng)計(jì)結(jié)果為=" + ret));
System.out.println(result);
}
8拇泣、拼接——joining
方法 |
描述 |
joining() |
將輸入元素(字符串類型)拼接成字符串,拼接輸入元素 |
joining(CharSequence delimiter) |
將輸入元素(字符串類型)拼接成字符串,將delimiter作為分隔符 |
joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) |
將輸入元素(字符串類型)拼接成字符串,將prefix作為前綴,suffix作為后綴 |
@Test
public void testCollectingAndThen() {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
String result = list.stream().collect(Collectors.joining());
System.out.println(result);//abc
String result2 = list.stream().collect(Collectors.joining("-"));
System.out.println(result2);//a-b-c
String result3 = list.stream().collect(Collectors.joining(",", "[", "]"));
System.out.println(result3);//[a,b,c]
}
9矮锈、mapping
方法 |
描述 |
mapping(Function<? super T, ? extends U> mapper,Collector<? super U, A, R> downstream) |
mapper(Function類型)和downstream(Collector類型)霉翔,在調(diào)用mapper之后,將調(diào)用結(jié)果的返回值作為downstream的輸入元素苞笨,再調(diào)用downstream |
@Test
public void testMapping() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("張三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("趙六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
String result = list.stream().collect(Collectors.mapping(Student::getName, Collectors.joining(",", "[", "]")));
System.out.println(result);//[李四,張三,王五,趙六]
}
10债朵、縮減——reducing
方法 |
描述 |
reducing(BinaryOperator<T> op) |
對(duì)輸入元素執(zhí)行縮減操作,對(duì)輸入的元素應(yīng)用op操作 |
reducing(T identity, BinaryOperator<T> op) |
對(duì)輸入元素執(zhí)行縮減操作,提供初始值identity |
reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op) |
對(duì)輸入元素執(zhí)行縮減操作,在對(duì)元素進(jìn)行op操作之前,先進(jìn)行mapper操作 |
@Test
public void testReducing() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//求和,返回Optional
Optional<Integer> result = list.stream().collect(Collectors.reducing((a, b) -> a + b));
if (result.isPresent()){
System.out.println(result.get());//6
}
//求和,返回Integer
Integer result2 = list.stream().collect(Collectors.reducing(0, (a, b) -> a + b));
System.out.println(result2);//6
//每個(gè)元素先平方,再求和
Integer result3 = list.stream().collect(Collectors.reducing(0, item -> item * item, (a, b) -> a + b));
System.out.println(result3);//14
}
11瀑凝、集合轉(zhuǎn)化——toCollection序芦、toList與toSet
方法 |
描述 |
toCollection(Supplier<C> collectionFactory) |
將輸入元素整理成集合,collectionFactory可以指定結(jié)果集合的類型粤咪,將輸入元素整理成集合 |
toList() |
將輸入元素整理成集合谚中,將輸入元素整理成ArrayList |
toSet() |
將輸入元素整理成集合,將輸入元素整理成HashSet |
@Test
public void testToCollection() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("張三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("趙六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
List<Student> toList = list.stream().filter(item -> item.getClassId().equals(1L)).collect(Collectors.toList());
Set<Student> toSet = list.stream().filter(item -> item.getClassId().equals(1L)).collect(Collectors.toSet());
ArrayList<Student> toCollection = list.stream().filter(item -> item.getClassId().equals(1L)).collect(Collectors.toCollection(ArrayList::new));
}
12、Map轉(zhuǎn)化——toMap與toConcurrentMap
方法 |
描述 |
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) |
將輸入元素整理成Map宪塔,keyMapper和valueMapper分別提供結(jié)果Map的鍵和值 |
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) |
將輸入元素整理成Map磁奖,mergeFunction對(duì)鍵相同的值進(jìn)行累積 |
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier) |
將輸入元素整理成Map,mapSupplier可以指定結(jié)果的Map類型 |
@Test
public void testToMap() {
List<Student> list = new ArrayList<>();
Student zhangSan = Student.builder().id(1L).name("張三").classId(1L).age(20).build();
Student liSi = Student.builder().id(2L).name("李四").classId(1L).age(21).build();
Student wangWu = Student.builder().id(3L).name("王五").classId(2L).age(21).build();
Student zhaoLiu = Student.builder().id(4L).name("趙六").classId(1L).age(21).build();
list.add(liSi);
list.add(zhangSan);
list.add(wangWu);
list.add(zhaoLiu);
//轉(zhuǎn)為map,存在相同的key的話會(huì)拋異常
Map<Long, String> map = list.stream().collect(Collectors.toMap(item -> item.getId(),
item -> item.getName()));
System.out.println(map);//{1=張三, 2=李四, 3=王五, 4=趙六}
//轉(zhuǎn)化為map,若key相等,取后一個(gè)
Student zhaoLiu2 = Student.builder().id(4L).name("趙六2").classId(1L).age(21).build();
list.add(zhaoLiu2);
Map<Long, String> map1 = list.stream().collect(Collectors.toMap(item -> item.getId(),
item -> item.getName(),
(a, b) -> b));
System.out.println(map1);//{1=張三, 2=李四, 3=王五, 4=趙六2}
//指定返回的map類型為TreeMap
TreeMap<Long, String> map3 = list.stream().collect(Collectors.toMap(item -> item.getId(),
item -> item.getName(),
(a, b) -> b,
TreeMap::new));
System.out.println(map3);//{1=張三, 2=李四, 3=王五, 4=趙六2}
}
參考文章:http://www.reibang.com/p/ac2bcf2f9d48
參考文章:https://blog.csdn.net/xiliunian/article/details/88773718
參考文章:https://blog.csdn.net/weixin_44187730/article/details/93737517