From 3c5313f0a71db58c66b67f1ff2a1c30d12f19a90 Mon Sep 17 00:00:00 2001 From: huangchengxing <841396397@qq.com> Date: Fri, 2 Sep 2022 16:14:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E9=94=AE=E5=80=BC=E5=AF=B9=E6=B5=81?= =?UTF-8?q?=E7=9A=84=E9=94=AE=E5=80=BC=E5=AF=B9=E5=AF=B9=E8=B1=A1=E4=BB=8E?= =?UTF-8?q?=E5=86=85=E9=83=A8=E7=B1=BB=E8=B0=83=E6=95=B4=E4=B8=BAAbstractM?= =?UTF-8?q?ap.SimpleImmutableEntry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/EntryStream.java | 190 ++++++++---------- .../hutool/core/stream/EntryStreamTest.java | 4 +- 2 files changed, 89 insertions(+), 105 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EntryStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EntryStream.java index d97e74a3f..81b7a6ecd 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EntryStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EntryStream.java @@ -1,6 +1,7 @@ package cn.hutool.core.stream; import cn.hutool.core.collection.ConcurrentHashSet; +import cn.hutool.core.collection.iter.IterUtil; import cn.hutool.core.map.multi.RowKeyTable; import cn.hutool.core.map.multi.Table; import cn.hutool.core.util.ObjUtil; @@ -13,9 +14,9 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; /** - *

针对键值对对象{@link Map.Entry}特化的增强流, - * 本身可视为一个元素类型为{@link Map.Entry}的{@link Stream}。
- * 用于支持流式处理{@link Map}集合中的、或具有潜在可能转为{@link Map}集合的数据。 + *

参考StreamEx的EntryStream与vavr的Map,是针对键值对对象{@link Map.Entry}特化的增强流实现。
+ * 本身可视为一个元素类型为{@link Map.Entry}的{@link Stream}, + * 用于支持流式处理{@link Map}集合中的、或其他键值对类型的数据。 * * @param 键类型 * @param 值类型 @@ -23,6 +24,11 @@ import java.util.stream.StreamSupport; */ public class EntryStream extends StreamWrapper, EntryStream> { + /** + * 默认的空键值对 + */ + private static final Map.Entry EMPTY_ENTRY = new AbstractMap.SimpleImmutableEntry<>(null, null); + /** * 根据键与值的集合创建键值对流,若两集合在相同下标的位置找不到对应的键或值,则使用{@code null}填充。
* 比如: {@code [1, 2, 3]}与{@code [1, 2]}合并,则得到{@code [{1=1}, {2=2}, {3=null}]}。 @@ -51,7 +57,7 @@ public class EntryStream extends StreamWrapper, EntryStrea final Iterator keyItr = keys.iterator(); final Iterator valueItr = values.iterator(); while (keyItr.hasNext() || valueItr.hasNext()) { - entries.add(new Entry<>( + entries.add(ofEntry( keyItr.hasNext() ? keyItr.next() : null, valueItr.hasNext() ? valueItr.next() : null )); @@ -106,7 +112,7 @@ public class EntryStream extends StreamWrapper, EntryStrea return empty(); } final Stream> stream = StreamSupport.stream(source.spliterator(), false) - .map(t -> new Entry<>(keyMapper.apply(t), valueMapper.apply(t))); + .map(t -> ofEntry(keyMapper.apply(t), valueMapper.apply(t))); return new EntryStream<>(stream); } @@ -121,7 +127,7 @@ public class EntryStream extends StreamWrapper, EntryStrea */ public static EntryStream of(Stream> stream) { return ObjUtil.isNull(stream) ? - empty() : new EntryStream<>(stream.map(Entry::new)); + empty() : new EntryStream<>(stream.map(EntryStream::ofEntry)); } /** @@ -142,19 +148,6 @@ public class EntryStream extends StreamWrapper, EntryStrea super(stream); } - // ================================ override ================================ - - /** - * 根据一个原始的流,返回一个新包装类实例 - * - * @param stream 流 - * @return 实现类 - */ - @Override - protected EntryStream convertToStreamImpl(Stream> stream) { - return new EntryStream<>(stream); - } - // ================================ 中间操作 ================================ /** @@ -164,7 +157,7 @@ public class EntryStream extends StreamWrapper, EntryStrea */ public EntryStream distinctByKey() { Set accessed = new ConcurrentHashSet<>(16); - return new EntryStream<>(stream.filter(e -> { + return convertToStreamImpl(stream.filter(e -> { K key = e.getKey(); if (accessed.contains(key)) { return false; @@ -181,7 +174,7 @@ public class EntryStream extends StreamWrapper, EntryStrea */ public EntryStream distinctByValue() { Set accessed = new ConcurrentHashSet<>(16); - return new EntryStream<>(stream.filter(e -> { + return convertToStreamImpl(stream.filter(e -> { V val = e.getValue(); if (accessed.contains(val)) { return false; @@ -229,6 +222,7 @@ public class EntryStream extends StreamWrapper, EntryStrea * * @return {@link EntryStream}实例 */ + @Override public EntryStream nonNull() { return super.filter(e -> ObjUtil.isNotNull(e) && ObjUtil.isNotNull(e.getKey()) && ObjUtil.isNotNull(e.getValue())); } @@ -304,8 +298,49 @@ public class EntryStream extends StreamWrapper, EntryStrea * @param value 值 * @return {@link EntryStream}实例 */ - public EntryStream push(K key, V value) { - return new EntryStream<>(Stream.concat(stream, Stream.of(new Entry<>(key, value)))); + public EntryStream append(K key, V value) { + return convertToStreamImpl(Stream.concat(stream, Stream.of(ofEntry(key, value)))); + } + + /** + * 项当前流队首追加元素 + * + * @param key 键 + * @param value 值 + * @return {@link EntryStream}实例 + */ + public EntryStream prepend(K key, V value) { + return convertToStreamImpl(Stream.concat(Stream.of(ofEntry(key, value)), stream)); + } + + /** + * 将输入元素转为流,返回一个前半段为当前流,后半段为新流的新{@link EasyStream}实例 + * + * @param entries 键值对 + * @return {@link EntryStream}实例 + */ + public EntryStream append(Iterable> entries) { + if (IterUtil.isEmpty(entries)) { + return this; + } + final Stream> contacted = StreamSupport.stream(entries.spliterator(), isParallel()) + .map(EntryStream::ofEntry); + return convertToStreamImpl(Stream.concat(stream, contacted)); + } + + /** + * 将输入元素转为流,返回一个前半段为新流,后半段为当前流的新{@link EasyStream}实例 + * + * @param entries 键值对 + * @return {@link EntryStream}实例 + */ + public EntryStream prepend(Iterable> entries) { + if (IterUtil.isEmpty(entries)) { + return this; + } + final Stream> contacted = StreamSupport.stream(entries.spliterator(), isParallel()) + .map(EntryStream::ofEntry); + return convertToStreamImpl(Stream.concat(contacted, stream)); } /** @@ -336,7 +371,7 @@ public class EntryStream extends StreamWrapper, EntryStrea public EntryStream mapKeys(Function mapper) { Objects.requireNonNull(mapper); return new EntryStream<>( - stream.map(e -> new Entry<>(mapper.apply(e.getKey()), e.getValue())) + stream.map(e -> ofEntry(mapper.apply(e.getKey()), e.getValue())) ); } @@ -350,7 +385,7 @@ public class EntryStream extends StreamWrapper, EntryStrea public EntryStream mapValues(Function mapper) { Objects.requireNonNull(mapper); return new EntryStream<>( - stream.map(e -> new Entry<>(e.getKey(), mapper.apply(e.getValue()))) + stream.map(e -> ofEntry(e.getKey(), mapper.apply(e.getValue()))) ); } @@ -417,7 +452,7 @@ public class EntryStream extends StreamWrapper, EntryStrea return new EntryStream<>( stream.flatMap(e -> keyMapper .apply(e.getKey()) - .map(newKey -> new Entry<>(newKey, e.getValue())) + .map(newKey -> ofEntry(newKey, e.getValue())) ) ); } @@ -441,7 +476,7 @@ public class EntryStream extends StreamWrapper, EntryStrea return new EntryStream<>( stream.flatMap(e -> valueMapper .apply(e.getValue()) - .map(newVal -> new Entry<>(e.getKey(), newVal)) + .map(newVal -> ofEntry(e.getKey(), newVal)) ) ); } @@ -625,7 +660,7 @@ public class EntryStream extends StreamWrapper, EntryStrea */ public EntryStream inverse() { return new EntryStream<>( - stream.map(e -> new Entry<>(e.getValue(), e.getKey())) + stream.map(e -> ofEntry(e.getValue(), e.getKey())) ); } @@ -683,85 +718,34 @@ public class EntryStream extends StreamWrapper, EntryStrea return super.noneMatch(e -> predicate.test(e.getKey(), e.getValue())); } + // ========================= private ========================= + /** - * {@link Map.Entry}的基本实现 + * 将键值对转为{@link AbstractMap.SimpleImmutableEntry} */ - static class Entry implements Map.Entry { + @SuppressWarnings("unchecked") + private static Map.Entry ofEntry(Map.Entry entry) { + return ObjUtil.defaultIfNull( + entry, e -> ofEntry(e.getKey(), e.getValue()), (Map.Entry)EMPTY_ENTRY + ); + } - /** - * 键 - */ - private final K key; - - /** - * 值 - */ - private V val; - - /** - * 创建一个简单键值对对象 - * - * @param key 键 - * @param val 值 - */ - public Entry(K key, V val) { - this.key = key; - this.val = val; - } - - /** - * 创建一个简单键值对对象 - * - * @param entry 键值对 - */ - public Entry(Map.Entry entry) { - if (ObjUtil.isNull(entry)) { - this.key = null; - this.val = null; - } else { - this.key = entry.getKey(); - this.val = entry.getValue(); - } - } - - /** - * 获取键 - * - * @return 键 - */ - @Override - public K getKey() { - return key; - } - - /** - * 获取值 - * - * @return 值 - */ - @Override - public V getValue() { - return val; - } - - /** - * 设置值 - * - * @param value 值 - * @return 旧值 - */ - @Override - public V setValue(V value) { - V old = val; - val = value; - return old; - } - - @Override - public String toString() { - return "{" + key + "=" + val + '}'; - } + /** + * 将键值对转为{@link AbstractMap.SimpleImmutableEntry} + */ + private static Map.Entry ofEntry(K key, V value) { + return new AbstractMap.SimpleImmutableEntry<>(key, value); + } + /** + * 根据一个原始的流,返回一个新包装类实例 + * + * @param stream 流 + * @return 实现类 + */ + @Override + public EntryStream convertToStreamImpl(Stream> stream) { + return new EntryStream<>(stream); } /** diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/EntryStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/EntryStreamTest.java index 3bbfe072c..c841d031f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/EntryStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/EntryStreamTest.java @@ -116,8 +116,8 @@ public class EntryStreamTest { Assert.assertEquals( 5, EntryStream.of(Arrays.asList(1, 2, 3), Function.identity(), Function.identity()) - .push(4, 4) - .push(5, 5) + .append(4, 4) + .append(5, 5) .count() );