您好,登錄后才能下訂單哦!
這篇文章主要介紹“Java中Stream的一些技巧分享”,在日常操作中,相信很多人在Java中Stream的一些技巧分享問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Java中Stream的一些技巧分享”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!
Stream
Filter
Foreach
Map
Sorted
Match
count
reduce
parallelStream
IntStream.range(a,b)
new Random().ints()
Supplier
Consumer
1. accept方法
2. andThen方法
ifPresent
Collect
1. 函數(shù)
2. Collector 接口
3. 工具函數(shù)
1. toList()
2.joining()
3.groupingBy()
4.reducing()
總結(jié)
使用這個(gè)方法創(chuàng)建一個(gè) Stream 對(duì)象。
new ArrayList<>().stream()
過濾器,里面?zhèn)鬟f一個(gè)函數(shù),這個(gè)函數(shù)的返回結(jié)果如果為 true 則保留這個(gè)元素,否則的話丟棄這個(gè)元素。
stringCollection .stream() .filter((s) -> s.startsWith("a")) .forEach(System.out::println);
遍歷,消費(fèi)。
stringCollection .stream() .filter((s) -> s.startsWith("a")) .forEach(System.out::println);
這個(gè)功能也是遍歷,但是他是有返回值的,而上面的 Foreach 是沒有返回值的,僅僅是單純的消費(fèi)。而且 Foreach 不能夠鏈?zhǔn)秸{(diào)用,因?yàn)闆]有返回值,但是 Map 沒問題。
stringCollection .stream() .map(String::toUpperCase) .sorted(Comparator.reverseOrder()) .forEach(System.out::println);
這個(gè)方法是用來排序的,里面?zhèn)鬟f的函數(shù)就是一個(gè)比較器,也可以不傳遞參數(shù),使用默認(rèn)的就好。
stringCollection .stream() .sorted(( x, y)-> y.length()-x.length()) .filter((s) -> s.startsWith("a")) .forEach(System.out::println);
根據(jù)在給定的 stream 對(duì)象中是否含有指定內(nèi)容返回 true 或者 false 。
具體的有:
allMatch
anyMatch
noneMatch
boolean anyStartsWithA = stringCollection .stream() .anyMatch((s) -> s.startsWith("a")); boolean allStartsWithA = stringCollection .stream() .allMatch((s) -> s.startsWith("a")); boolean noneStartsWithZ = stringCollection .stream() .noneMatch((s) -> s.startsWith("z"));
計(jì)算集合中的元素的個(gè)數(shù)。
long startsWithB = stringCollection .stream() .filter((s) -> s.startsWith("b")) .count();
這個(gè)函數(shù)就是類似于斐波那契數(shù)列,每次傳遞的參數(shù)是上一次的結(jié)果和從集合中取出的新元素。第一次默認(rèn)取出了第一個(gè)元素和第二個(gè)元素。
簡(jiǎn)單的例子就是,第一次取出 0,1 第二次取出 第一次reduce的結(jié)果作為第一個(gè)參數(shù),取出 2 作為第二個(gè)參數(shù),以此類推。
Optional<String> reduced = stringCollection .stream() .sorted() .reduce((s1, s2) -> s1 + "#" + s2);
并行的 steam 流,可以進(jìn)行并行處理,這樣會(huì)效率更高。在使用stream.foreach時(shí)這個(gè)遍歷沒有線程安全問題,但是使用parallelStream就會(huì)有線程安全問題,所有在parallelStream里面使用的外部變量,比如集合一定要使用線程安全集合,不然就會(huì)引發(fā)多線程安全問題。如果說需要保證安全性需要使用 reduce 和 collect,不過這個(gè)用起來超級(jí)麻煩?。?!
long count = values.parallelStream().sorted().count();
可以直接生成 從 a 到 b 的整數(shù)這里還是遵循編程語言的大多數(shù)約定,那就是含頭不含尾。
IntStream.range(0, 10) .forEach(System.out::println);
輸出的結(jié)果是
0
1
2
3
4
5
6
7
8
9
獲取一系列的隨機(jī)值,這個(gè)接口出來的數(shù)據(jù)是連續(xù)不斷的,所以需要用limit來限制一下。
new Random().ints().limit(10).forEach(System.out::println);
Supplier<String> stringSupplier=String::new; stringSupplier.get();
該接口就一個(gè)抽象方法get方法,不用傳入任何參數(shù),直接返回一個(gè)泛型T的實(shí)例.就如同無參構(gòu)造一樣
該函數(shù)式接口的唯一的抽象方法,接收一個(gè)參數(shù),沒有返回值.
在執(zhí)行完調(diào)用者方法后再執(zhí)行傳入?yún)?shù)的方法.
public class ConsumerTest { public static void main(String[] args) { Consumer<Integer> consumer = (x) -> { int num = x * 2; System.out.println(num); }; Consumer<Integer> consumer1 = (x) -> { int num = x * 3; System.out.println(num); }; consumer.andThen(consumer1).accept(10); }
先執(zhí)行了 consumer.accept(10) 然后執(zhí)行了 consumer1.accept(10)
針對(duì)一個(gè)optional 如果有值的話就執(zhí)行否則不執(zhí)行。
IntStream .builder() .add(1) .add(3) .add(5) .add(7) .add(11) .build() .average() .ifPresent(System.out::println);
average 執(zhí)行結(jié)果就是一個(gè) optional
他有兩種調(diào)用方式
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner); <R, A> R collect(Collector<? super T, A, R> collector);
下面主要介紹一下這兩種方式的使用方法:
第一種調(diào)用方式的接口如下
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
supplier 這個(gè)參數(shù)就是提供一個(gè)容器,可以看到最后 collect 操作的結(jié)果是一個(gè) R 類型變量,而 supplier 接口最后需要返回的也是一個(gè) R 類型的變量,所以說這里返回的是收集元素的容器。
accumulator 參數(shù),看到這個(gè)函數(shù)的定義是傳入一個(gè) R 容器,后面則是 T 類型的元素,需要將這個(gè) T 放到 R 容器中,即這一步是用來將元素添加到容器中的操作。
conbiner 這個(gè)參數(shù)是兩個(gè)容器,即當(dāng)出現(xiàn)多個(gè)容器的時(shí)候容器如何進(jìn)行聚合。
一個(gè)簡(jiǎn)單的例子:
String concat = stringStream.collect(StringBuilder::new, StringBuilder::append,StringBuilder::append).toString(); //等價(jià)于上面,這樣看起來應(yīng)該更加清晰 String concat = stringStream.collect(() -> new StringBuilder(),(l, x) -> l.append(x), (r1, r2) -> r1.append(r2)).toString();
第二種方案是更高級(jí)的用法采用了 Collector 接口:
<R, A> R collect(Collector<? super T, A, R> collector);
可以看到他返回的還是一個(gè) R 類型的變量,也就是容器。
Collector接口是使得collect操作強(qiáng)大的終極武器,對(duì)于絕大部分操作可以分解為旗下主要步驟,提供初始容器->加入元素到容器->并發(fā)下多容器聚合->對(duì)聚合后結(jié)果進(jìn)行操作
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; } }
可以看到我們可以直接 new CollectorImpl 然后將這些函數(shù)傳入,另外還有一種簡(jiǎn)單的方式就是 使用 Collector.of()依然可以直接傳入函數(shù)。和 new CollectorImpl 是等價(jià)的。
容器: ArrayList::new
加入容器操作: List::add
多容器合并: left.addAll(right); return left;
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); }
容器: StringBuilder::new
加入容器操作: StringBuilder::append
多容器合并: r1.append(r2); return r1;
聚合后的結(jié)果操作: StringBuilder::toString
public static Collector<CharSequence, ?, String> joining() { return new CollectorImpl<CharSequence, StringBuilder, String>( StringBuilder::new, StringBuilder::append, (r1, r2) -> { r1.append(r2); return r1; }, StringBuilder::toString, CH_NOID); }
roupingBy是toMap的一種高級(jí)方式,彌補(bǔ)了toMap對(duì)值無法提供多元化的收集操作,比如對(duì)于返回Map<T,List<E>>這樣的形式toMap就不是那么順手,那么groupingBy的重點(diǎn)就是對(duì)Key和Value值的處理封裝.分析如下代碼,其中classifier是對(duì)key值的處理,mapFactory則是指定Map的容器具體類型,downstream為對(duì)Value的收集操作.
public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream) { ....... }
一個(gè)簡(jiǎn)單的例子
//原生形式 Lists.<Person>newArrayList().stream() .collect(() -> new HashMap<Integer,List<Person>>(), (h, x) -> { List<Person> value = h.getOrDefault(x.getType(), Lists.newArrayList()); value.add(x); h.put(x.getType(), value); }, HashMap::putAll ); //groupBy形式 Lists.<Person>newArrayList().stream() .collect(Collectors.groupingBy(Person::getType, HashMap::new, Collectors.toList())); //因?yàn)閷?duì)值有了操作,因此我可以更加靈活的對(duì)值進(jìn)行轉(zhuǎn)換 Lists.<Person>newArrayList().stream() .collect(Collectors.groupingBy(Person::getType, HashMap::new, Collectors.mapping(Person::getName,Collectors.toSet()))); // 還有一種比較簡(jiǎn)單的使用方式 只需要傳遞一個(gè)參數(shù)按照key來劃分 Map<Integer, List<Person>> personsByAge = persons .stream() .collect(Collectors.groupingBy(p -> p.age));
reducing是針對(duì)單個(gè)值的收集,其返回結(jié)果不是集合家族的類型,而是單一的實(shí)體類T
容器: boxSupplier(identity),這里包裹用的是一個(gè)長(zhǎng)度為1的Object[]數(shù)組,至于原因自然是不可變類型的鍋
加入容器操作: a[0] = op.apply(a[0], t)
多容器合并: a[0] = op.apply(a[0], b[0]); return a;
聚合后的結(jié)果操作: 結(jié)果自然是Object[0]所包裹的數(shù)據(jù)a -> a[0]
優(yōu)化操作狀態(tài)字段: CH_NOID
public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) { return new CollectorImpl<>( boxSupplier(identity), (a, t) -> { a[0] = op.apply(a[0], t); }, (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; }, a -> a[0], CH_NOID); }
簡(jiǎn)單來說這個(gè)地方做的事情和 reduce 是一樣的,第一個(gè) id 傳入的就是 reduce 的初始值,只是他把它包裝成一個(gè) 長(zhǎng)度為1的數(shù)組了。
//原生操作 final Integer[] integers = Lists.newArrayList(1, 2, 3, 4, 5) .stream() .collect(() -> new Integer[]{0}, (a, x) -> a[0] += x, (a1, a2) -> a1[0] += a2[0]); //reducing操作 final Integer collect = Lists.newArrayList(1, 2, 3, 4, 5) .stream() .collect(Collectors.reducing(0, Integer::sum)); //當(dāng)然Stream也提供了reduce操作 final Integer collect = Lists.newArrayList(1, 2, 3, 4, 5) .stream().reduce(0, Integer::sum)
到此,關(guān)于“Java中Stream的一些技巧分享”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。