From ae628d5a2c1b7efb98aebfb55d73d139f13d54f1 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 31 Mar 2022 02:09:12 +0800 Subject: [PATCH] add methods --- .../cn/hutool/core/collection/ArrayIter.java | 3 +- .../cn/hutool/core/collection/CollUtil.java | 15 +- .../cn/hutool/core/collection/CopiedIter.java | 16 +- .../cn/hutool/core/collection/IterUtil.java | 194 +++++++++++++++--- .../hutool/core/collection/IterableIter.java | 1 + .../hutool/core/collection/NodeListIter.java | 63 ++++++ .../core/collection/ResettableIter.java | 18 ++ .../java/cn/hutool/core/text/StrJoiner.java | 11 +- .../hutool/core/collection/IterUtilTest.java | 8 + 9 files changed, 277 insertions(+), 52 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/collection/NodeListIter.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/collection/ResettableIter.java diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/ArrayIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/ArrayIter.java index 5fa25cdc7..94db0ef6d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/ArrayIter.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/ArrayIter.java @@ -11,7 +11,7 @@ import java.util.NoSuchElementException; * @author Looly * @since 4.1.1 */ -public class ArrayIter implements IterableIter, Serializable { +public class ArrayIter implements IterableIter, ResettableIter, Serializable { private static final long serialVersionUID = 1L; /** @@ -126,6 +126,7 @@ public class ArrayIter implements IterableIter, Serializable { /** * 重置数组位置 */ + @Override public void reset() { this.index = this.startIndex; } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java index 21120cd25..b5a024124 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java @@ -2212,17 +2212,8 @@ public class CollUtil { final List list = ((List) collection); return list.get(index); } else { - int i = 0; - for (T t : collection) { - if (i > index) { - break; - } else if (i == index) { - return t; - } - i++; - } + return IterUtil.get(collection.iterator(), index); } - return null; } /** @@ -2303,7 +2294,9 @@ public class CollUtil { * @return 元素类型,当列表为空或元素全部为null时,返回null * @see IterUtil#getElementType(Iterable) * @since 3.0.8 + * @deprecated 请使用 {@link IterUtil#getElementType(Iterable)} */ + @Deprecated public static Class getElementType(Iterable iterable) { return IterUtil.getElementType(iterable); } @@ -2315,7 +2308,9 @@ public class CollUtil { * @return 元素类型,当列表为空或元素全部为null时,返回null * @see IterUtil#getElementType(Iterator) * @since 3.0.8 + * @deprecated 请使用 {@link IterUtil#getElementType(Iterator)} */ + @Deprecated public static Class getElementType(Iterator iterator) { return IterUtil.getElementType(iterator); } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CopiedIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/CopiedIter.java index e0a68bff1..568f34494 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CopiedIter.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CopiedIter.java @@ -16,7 +16,6 @@ import java.util.List; *

* 需要注意的是,在构造此对象时需要保证原子性(原对象不被修改),最好加锁构造此对象,构造完毕后解锁。 * - * * @param 元素类型 * @author Looly * @since 3.0.7 @@ -26,16 +25,24 @@ public class CopiedIter implements IterableIter, Serializable { private final Iterator listIterator; - public static CopiedIter copyOf(Iterator iterator){ + /** + * 根据已有{@link Iterator},返回新的{@code CopiedIter} + * + * @param iterator {@link Iterator} + * @param 元素类型 + * @return {@code CopiedIter} + */ + public static CopiedIter copyOf(Iterator iterator) { return new CopiedIter<>(iterator); } /** * 构造 + * * @param iterator 被复制的Iterator */ public CopiedIter(Iterator iterator) { - final List eleList = CollUtil.newArrayList(iterator); + final List eleList = ListUtil.toList(iterator); this.listIterator = eleList.iterator(); } @@ -51,10 +58,11 @@ public class CopiedIter implements IterableIter, Serializable { /** * 此对象不支持移除元素 + * * @throws UnsupportedOperationException 当调用此方法时始终抛出此异常 */ @Override - public void remove() throws UnsupportedOperationException{ + public void remove() throws UnsupportedOperationException { throw new UnsupportedOperationException("This is a read-only iterator."); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/IterUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/IterUtil.java index ddcafe36b..ce967a608 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/IterUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/IterUtil.java @@ -8,12 +8,17 @@ import cn.hutool.core.lang.Matcher; import cn.hutool.core.lang.func.Func1; import cn.hutool.core.map.MapUtil; import cn.hutool.core.text.StrJoiner; +import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; +import com.sun.xml.internal.ws.util.xml.NodeListIterator; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; @@ -21,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.function.Consumer; import java.util.function.Function; /** @@ -511,11 +517,7 @@ public class IterUtil { * @since 4.0.6 */ public static List toList(Iterator iter) { - final List list = new ArrayList<>(); - while (iter.hasNext()) { - list.add(iter.next()); - } - return list; + return ListUtil.toList(iter); } /** @@ -543,17 +545,35 @@ public class IterUtil { } /** - * 获取集合的第一个元素 + * 遍历{@link Iterator},获取指定index位置的元素 + * + * @param iterator {@link Iterator} + * @param index 位置 + * @param 元素类型 + * @return 元素,找不到元素返回{@code null} + * @since 5.8.0 + */ + public static E get(final Iterator iterator, int index) throws IndexOutOfBoundsException { + Assert.isTrue(index >= 0, "[index] must be >= 0"); + while (iterator.hasNext()) { + index--; + if (-1 == index) { + return iterator.next(); + } + iterator.next(); + } + return null; + } + + /** + * 获取集合的第一个元素,如果集合为空(null或者空集合),返回{@code null} * * @param 集合元素类型 * @param iterable {@link Iterable} - * @return 第一个元素 + * @return 第一个元素,为空返回{@code null} */ public static T getFirst(Iterable iterable) { - if (null == iterable) { - return null; - } - return getFirst(iterable.iterator()); + return getFirst(getIter(iterable)); } /** @@ -579,10 +599,7 @@ public class IterUtil { * @return 第一个元素 */ public static T getFirst(Iterator iterator) { - if (null != iterator && iterator.hasNext()) { - return iterator.next(); - } - return null; + return get(iterator, 0); } /** @@ -627,29 +644,22 @@ public class IterUtil { * @return 元素类型,当列表为空或元素全部为null时,返回null */ public static Class getElementType(Iterable iterable) { - if (null != iterable) { - final Iterator iterator = iterable.iterator(); - return getElementType(iterator); - } - return null; + return getElementType(getIter(iterable)); } /** * 获得{@link Iterator}对象的元素类型(通过第一个非空元素判断)
* 注意,此方法至少会调用多次next方法 * - * @param iterator {@link Iterator} - * @return 元素类型,当列表为空或元素全部为null时,返回null + * @param iterator {@link Iterator},为 {@code null}返回{@code null} + * @return 元素类型,当列表为空或元素全部为{@code null}时,返回{@code null} */ public static Class getElementType(Iterator iterator) { - final Iterator iter2 = new CopiedIter<>(iterator); - while (iter2.hasNext()) { - final Object t = iter2.next(); - if (null != t) { - return t.getClass(); - } + if (null == iterator) { + return null; } - return null; + final Object ele = getFirstNoneNull(iterator); + return null == ele ? null : ele.getClass(); } /** @@ -751,9 +761,9 @@ public class IterUtil { /** * 获取一个新的 {@link FilterIter},用于过滤指定元素 * - * @param iterator 被包装的 {@link Iterator} - * @param filter 过滤断言,当{@link Filter#accept(Object)}为{@code true}时保留元素,{@code false}抛弃元素 - * @param 元素类型 + * @param iterator 被包装的 {@link Iterator} + * @param filter 过滤断言,当{@link Filter#accept(Object)}为{@code true}时保留元素,{@code false}抛弃元素 + * @param 元素类型 * @return {@link FilterIter} * @since 5.8.0 */ @@ -924,4 +934,124 @@ public class IterUtil { } } } + + /** + * 遍历{@link Iterator}
+ * 当consumer为{@code null}表示不处理,但是依旧遍历{@link Iterator} + * + * @param iterator {@link Iterator} + * @param consumer 节点消费,{@code null}表示不处理 + * @param 元素类型 + * @since 5.8.0 + */ + public static void forEach(final Iterator iterator, final Consumer consumer) { + if (iterator != null) { + while (iterator.hasNext()) { + final E element = iterator.next(); + if (null != consumer) { + consumer.accept(element); + } + } + } + } + + /** + * 拼接 {@link Iterator}为字符串 + * + * @param iterator {@link Iterator} + * @param 元素类型 + * @return 字符串 + * @since 5.8.0 + */ + public static String toStr(final Iterator iterator) { + return toStr(iterator, ObjectUtil::toString); + } + + /** + * 拼接 {@link Iterator}为字符串 + * + * @param iterator {@link Iterator} + * @param transFunc 元素转字符串函数 + * @param 元素类型 + * @return 字符串 + * @since 5.8.0 + */ + public static String toStr(final Iterator iterator, final Function transFunc) { + return toStr(iterator, transFunc, ", ", "[", "]"); + } + + /** + * 拼接 {@link Iterator}为字符串 + * + * @param iterator {@link Iterator} + * @param transFunc 元素转字符串函数 + * @param delimiter 分隔符 + * @param prefix 前缀 + * @param suffix 后缀 + * @param 元素类型 + * @return 字符串 + * @since 5.8.0 + */ + public static String toStr(final Iterator iterator, + final Function transFunc, + final String delimiter, + final String prefix, + final String suffix) { + final StrJoiner strJoiner = StrJoiner.of(delimiter, prefix, suffix); + strJoiner.append(iterator, transFunc); + return strJoiner.toString(); + } + + /** + * 从给定的对象中获取可能存在的{@link Iterator},规则如下: + *

    + *
  • null - null
  • + *
  • Iterator - 直接返回
  • + *
  • Enumeration - {@link EnumerationIter}
  • + *
  • Collection - 调用{@link Collection#iterator()}
  • + *
  • Map - Entry的{@link Iterator}
  • + *
  • Dictionary - values (elements) enumeration returned as iterator
  • + *
  • array - {@link ArrayIter}
  • + *
  • NodeList - {@link NodeListIter}
  • + *
  • Node - 子节点
  • + *
  • object with iterator() public method,通过反射访问
  • + *
  • object - 单对象的{@link ArrayIter}
  • + *
+ * + * @param obj 可以获取{@link Iterator}的对象 + * @return {@link Iterator},如果提供对象为{@code null},返回{@code null} + */ + public static Iterator getIter(final Object obj) { + if (obj == null) { + return null; + } else if (obj instanceof Iterator) { + return (Iterator) obj; + } else if (obj instanceof Iterable) { + return ((Iterable) obj).iterator(); + } else if (ArrayUtil.isArray(obj)) { + return new ArrayIter<>(obj); + } else if (obj instanceof Enumeration) { + return new EnumerationIter<>((Enumeration) obj); + } else if (obj instanceof Map) { + return ((Map) obj).entrySet().iterator(); + } else if (obj instanceof NodeList) { + return new NodeListIterator((NodeList) obj); + } else if (obj instanceof Node) { + // 遍历子节点 + return new NodeListIterator(((Node) obj).getChildNodes()); + } else if (obj instanceof Dictionary) { + return new EnumerationIter<>(((Dictionary) obj).elements()); + } + + // 反射获取 + try { + final Object iterator = ReflectUtil.invoke(obj, "iterator"); + if (iterator instanceof Iterator) { + return (Iterator) iterator; + } + } catch (final RuntimeException ignore) { + // ignore + } + return new ArrayIter<>(new Object[]{obj}); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/IterableIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/IterableIter.java index 5a58b4261..e5e91e5db 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/IterableIter.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/IterableIter.java @@ -10,6 +10,7 @@ import java.util.Iterator; * @since 5.7.14 */ public interface IterableIter extends Iterable, Iterator { + @Override default Iterator iterator() { return this; diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/NodeListIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/NodeListIter.java new file mode 100644 index 000000000..e12925542 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/collection/NodeListIter.java @@ -0,0 +1,63 @@ +package cn.hutool.core.collection; + +import cn.hutool.core.lang.Assert; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * 包装 {@link NodeList} 的{@link Iterator} + *

+ * 此 iterator 不支持 {@link #remove()} 方法。 + * + * @author apache commons,looly + * @see NodeList + * @since 5.8.0 + */ +public class NodeListIter implements ResettableIter { + + private final NodeList nodeList; + /** + * 当前位置索引 + */ + private int index = 0; + + /** + * 构造, 根据给定{@link NodeList} 创建{@code NodeListIterator} + * + * @param nodeList {@link NodeList},非空 + */ + public NodeListIter(final NodeList nodeList) { + this.nodeList = Assert.notNull(nodeList, "NodeList must not be null."); + } + + @Override + public boolean hasNext() { + return nodeList != null && index < nodeList.getLength(); + } + + @Override + public Node next() { + if (nodeList != null && index < nodeList.getLength()) { + return nodeList.item(index++); + } + throw new NoSuchElementException("underlying nodeList has no more elements"); + } + + /** + * Throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException always + */ + @Override + public void remove() { + throw new UnsupportedOperationException("remove() method not supported for a NodeListIterator."); + } + + @Override + public void reset() { + this.index = 0; + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/ResettableIter.java b/hutool-core/src/main/java/cn/hutool/core/collection/ResettableIter.java new file mode 100644 index 000000000..837c7dcda --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/collection/ResettableIter.java @@ -0,0 +1,18 @@ +package cn.hutool.core.collection; + +import java.util.Iterator; + +/** + * 支持重置的{@link Iterator} 接口
+ * 通过实现{@link #reset()},重置此{@link Iterator}后可实现复用重新遍历 + * + * @param 元素类型 + * @since 5.8.0 + */ +public interface ResettableIter extends Iterator { + + /** + * 重置,重置后可重新遍历 + */ + void reset(); +} diff --git a/hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java b/hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java index 13f252fcb..4124f8d27 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/StrJoiner.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.ArrayIter; import cn.hutool.core.collection.IterUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import java.io.IOException; @@ -211,7 +212,7 @@ public class StrJoiner implements Appendable, Serializable { } else if (obj instanceof Iterable) { append(((Iterable) obj).iterator()); } else { - append(String.valueOf(obj)); + append(ObjectUtil.toString(obj)); } return this; } @@ -261,24 +262,24 @@ public class StrJoiner implements Appendable, Serializable { /** * 追加{@link Iterator}中的元素到拼接器中 * - * @param 元素类型 + * @param 元素类型 * @param iterable 元素列表 * @param toStrFunc 元素对象转换为字符串的函数 * @return this */ - public StrJoiner append(Iterable iterable, Function toStrFunc) { + public StrJoiner append(Iterable iterable, Function toStrFunc) { return append(IterUtil.getIter(iterable), toStrFunc); } /** * 追加{@link Iterator}中的元素到拼接器中 * - * @param 元素类型 + * @param 元素类型 * @param iterator 元素列表 * @param toStrFunc 元素对象转换为字符串的函数 * @return this */ - public StrJoiner append(Iterator iterator, Function toStrFunc) { + public StrJoiner append(Iterator iterator, Function toStrFunc) { if (null != iterator) { while (iterator.hasNext()) { append(toStrFunc.apply(iterator.next())); diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/IterUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/IterUtilTest.java index 6e74468ba..f9cfb17e9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/collection/IterUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/collection/IterUtilTest.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -136,4 +137,11 @@ public class IterUtilTest { Assert.assertEquals(1, filtered.size()); Assert.assertEquals("3", filtered.get(0)); } + + @Test + public void getTest() { + HashSet set = CollUtil.set(true, "A", "B", "C", "D"); + String str = IterUtil.get(set.iterator(), 2); + Assert.assertEquals("C", str); + } }