diff --git a/src/main/java/org/cactoos/list/ArrayAsIterable.java b/src/main/java/org/cactoos/list/ArrayAsIterable.java index 31eee32980..5ceb323499 100644 --- a/src/main/java/org/cactoos/list/ArrayAsIterable.java +++ b/src/main/java/org/cactoos/list/ArrayAsIterable.java @@ -25,7 +25,6 @@ import java.util.Arrays; import java.util.Iterator; -import org.cactoos.func.UncheckedScalar; /** * Array as iterable. @@ -42,7 +41,7 @@ public final class ArrayAsIterable implements Iterable { /** * The array. */ - private final UncheckedScalar> result; + private final X[] array; /** * Ctor. @@ -51,12 +50,12 @@ public final class ArrayAsIterable implements Iterable { @SafeVarargs @SuppressWarnings("varargs") public ArrayAsIterable(final X... items) { - this.result = new UncheckedScalar<>(() -> Arrays.asList(items)); + this.array = items; } @Override public Iterator iterator() { - return this.result.asValue().iterator(); + return Arrays.asList(this.array).iterator(); } } diff --git a/src/main/java/org/cactoos/list/IterableAsList.java b/src/main/java/org/cactoos/list/IterableAsList.java index d2a4a1fd98..918f3049e2 100644 --- a/src/main/java/org/cactoos/list/IterableAsList.java +++ b/src/main/java/org/cactoos/list/IterableAsList.java @@ -23,32 +23,40 @@ */ package org.cactoos.list; -import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.ListIterator; -import org.cactoos.func.StickyScalar; -import org.cactoos.func.UncheckedScalar; /** * Iterable as {@link List}. * + *

This class should be used very carefully. You must understand that + * it will fetch the entire content of the encapsulated {@link List} on each + * method call. It doesn't cache the data anyhow.

+ * + *

If you don't need this {@link List} to re-fresh its content on every call, + * by doing round-trips to the encapsulated iterable, use + * {@link StickyList}.

+ * *

There is no thread-safety guarantee. * * @author Alexey Semenyuk (semenyukalexey88@gmail.com) * @author Kirill (g4s8.public@gmail.com) + * @author Yegor Bugayenko (yegor256@gmail.com) * @version $Id$ * @param List type + * @see StickyList * @since 0.1 */ @SuppressWarnings("PMD.TooManyMethods") public final class IterableAsList implements List { /** - * List source. + * The source. */ - private final UncheckedScalar> list; + private final Iterable iterable; /** * Ctor. @@ -64,51 +72,41 @@ public IterableAsList(final T... array) { /** * Ctor. * - * @param iterable An {@link Iterable} + * @param src An {@link Iterable} */ - public IterableAsList(final Iterable iterable) { - this.list = new UncheckedScalar<>( - new StickyScalar<>( - () -> { - final List temp = new ArrayList<>(0); - for (final T elem : iterable) { - temp.add(elem); - } - return temp; - } - ) - ); + public IterableAsList(final Iterable src) { + this.iterable = src; } @Override public int size() { - return this.list.asValue().size(); + return new LengthOfIterable(this.iterable).asValue(); } @Override public boolean isEmpty() { - return this.list.asValue().isEmpty(); + return !this.iterable.iterator().hasNext(); } @Override public boolean contains(final Object object) { - return this.list.asValue().contains(object); + return this.list().contains(object); } @Override public Iterator iterator() { - return this.list.asValue().iterator(); + return this.iterable.iterator(); } @Override public Object[] toArray() { - return this.list.asValue().toArray(); + return this.list().toArray(); } @Override @SuppressWarnings("PMD.UseVarargs") public Y[] toArray(final Y[] array) { - return this.list.asValue().toArray(array); + return this.list().toArray(array); } @Override @@ -127,7 +125,7 @@ public boolean remove(final Object object) { @Override public boolean containsAll(final Collection collection) { - return this.list.asValue().containsAll(collection); + return this.list().containsAll(collection); } @Override @@ -168,7 +166,7 @@ public void clear() { @Override public T get(final int index) { - return this.list.asValue().get(index); + return this.list().get(index); } @Override @@ -194,26 +192,38 @@ public T remove(final int index) { @Override public int indexOf(final Object object) { - return this.list.asValue().indexOf(object); + return this.list().indexOf(object); } @Override public int lastIndexOf(final Object object) { - return this.list.asValue().lastIndexOf(object); + return this.list().lastIndexOf(object); } @Override public ListIterator listIterator() { - return this.list.asValue().listIterator(); + return this.list().listIterator(); } @Override public ListIterator listIterator(final int index) { - return this.list.asValue().listIterator(index); + return this.list().listIterator(index); } @Override public List subList(final int fromindex, final int toindex) { - return this.list.asValue().subList(fromindex, toindex); + return this.list().subList(fromindex, toindex); + } + + /** + * Build a list. + * @return List + */ + private List list() { + final List list = new LinkedList<>(); + for (final T item : this.iterable) { + list.add(item); + } + return list; } } diff --git a/src/main/java/org/cactoos/list/IterableAsMap.java b/src/main/java/org/cactoos/list/IterableAsMap.java index b1f316434c..791f7c25d0 100644 --- a/src/main/java/org/cactoos/list/IterableAsMap.java +++ b/src/main/java/org/cactoos/list/IterableAsMap.java @@ -27,78 +27,76 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -import org.cactoos.func.StickyScalar; -import org.cactoos.func.UncheckedScalar; /** * Iterable as {@link Map}. * + *

This class should be used very carefully. You must understand that + * it will fetch the entire content of the encapsulated {@link Map} on each + * method call. It doesn't cache the data anyhow.

+ * + *

If you don't need this {@link Map} to re-fresh its content on every call, + * by doing round-trips to the encapsulated iterable, use + * {@link StickyMap}.

+ * *

There is no thread-safety guarantee. * * @author Yegor Bugayenko (yegor256@gmail.com) * @version $Id$ * @param Type of key * @param Type of value + * @see StickyMap * @since 0.4 */ +@SuppressWarnings("PMD.TooManyMethods") public final class IterableAsMap implements Map { /** - * The map. + * The iterable. */ - private final UncheckedScalar> map; + private final Iterable> entries; /** * Ctor. - * @param entries Entries for the map + * @param list List of entries */ @SafeVarargs @SuppressWarnings("varargs") - public IterableAsMap(final Map.Entry... entries) { - this(new ArrayAsIterable<>(entries)); + public IterableAsMap(final Map.Entry... list) { + this(new ArrayAsIterable<>(list)); } /** * Ctor. - * @param entries Entries for the map + * @param list Entries for the entries */ - public IterableAsMap(final Iterable> entries) { - this.map = new UncheckedScalar<>( - new StickyScalar<>( - () -> { - final Map temp = new HashMap<>(0); - for (final Map.Entry entry : entries) { - temp.put(entry.getKey(), entry.getValue()); - } - return temp; - } - ) - ); + public IterableAsMap(final Iterable> list) { + this.entries = list; } @Override public int size() { - return this.map.asValue().size(); + return new LengthOfIterable(this.entries).asValue(); } @Override public boolean isEmpty() { - return this.map.asValue().isEmpty(); + return !this.entries.iterator().hasNext(); } @Override public boolean containsKey(final Object key) { - return this.map.asValue().containsKey(key); + return this.map().containsKey(key); } @Override public boolean containsValue(final Object value) { - return this.map.asValue().containsValue(value); + return this.map().containsValue(value); } @Override public Y get(final Object key) { - return this.map.asValue().get(key); + return this.map().get(key); } @Override @@ -116,7 +114,7 @@ public Y remove(final Object key) { } @Override - public void putAll(final Map entries) { + public void putAll(final Map list) { throw new UnsupportedOperationException( "#putAll() is not supported" ); @@ -131,17 +129,29 @@ public void clear() { @Override public Set keySet() { - return this.map.asValue().keySet(); + return this.map().keySet(); } @Override public Collection values() { - return this.map.asValue().values(); + return this.map().values(); } @Override public Set> entrySet() { - return this.map.asValue().entrySet(); + return this.map().entrySet(); + } + + /** + * Make a map. + * @return Map + */ + private Map map() { + final Map temp = new HashMap<>(0); + for (final Map.Entry entry : this.entries) { + temp.put(entry.getKey(), entry.getValue()); + } + return temp; } } diff --git a/src/main/java/org/cactoos/list/MapAsProperties.java b/src/main/java/org/cactoos/list/MapAsProperties.java index a6abc60768..d70723b306 100644 --- a/src/main/java/org/cactoos/list/MapAsProperties.java +++ b/src/main/java/org/cactoos/list/MapAsProperties.java @@ -27,8 +27,6 @@ import java.util.Map; import java.util.Properties; import org.cactoos.Scalar; -import org.cactoos.func.StickyScalar; -import org.cactoos.func.UncheckedScalar; /** * Map as {@link java.util.Properties}. @@ -42,9 +40,9 @@ public final class MapAsProperties implements Scalar { /** - * The result. + * The map. */ - private final UncheckedScalar result; + private final Map map; /** * Ctor. @@ -65,27 +63,21 @@ public MapAsProperties(final Map.Entry... entries) { /** * Ctor. - * @param map The map with properties + * @param src The map with properties */ - public MapAsProperties(final Map map) { - this.result = new UncheckedScalar<>( - new StickyScalar<>( - () -> { - final Properties props = new Properties(); - for (final Map.Entry entry : map.entrySet()) { - props.setProperty( - entry.getKey().toString(), - entry.getValue().toString() - ); - } - return props; - } - ) - ); + public MapAsProperties(final Map src) { + this.map = src; } @Override public Properties asValue() { - return this.result.asValue(); + final Properties props = new Properties(); + for (final Map.Entry entry : this.map.entrySet()) { + props.setProperty( + entry.getKey().toString(), + entry.getValue().toString() + ); + } + return props; } } diff --git a/src/main/java/org/cactoos/list/RepeatIterable.java b/src/main/java/org/cactoos/list/RepeatIterable.java index f03a57cc8d..54ec35e22b 100644 --- a/src/main/java/org/cactoos/list/RepeatIterable.java +++ b/src/main/java/org/cactoos/list/RepeatIterable.java @@ -24,6 +24,8 @@ package org.cactoos.list; import java.util.Iterator; +import org.cactoos.Scalar; +import org.cactoos.func.UncheckedScalar; /** * Repeat an element. @@ -41,7 +43,7 @@ public final class RepeatIterable implements Iterable { /** * Element to repeat. */ - private final T element; + private final UncheckedScalar element; /** * Repeat count. @@ -50,11 +52,28 @@ public final class RepeatIterable implements Iterable { /** * Ctor. - * * @param elm To repeat * @param cnt Count */ public RepeatIterable(final T elm, final int cnt) { + this(() -> elm, cnt); + } + + /** + * Ctor. + * @param elm To repeat + * @param cnt Count + */ + public RepeatIterable(final Scalar elm, final int cnt) { + this(new UncheckedScalar(elm), cnt); + } + + /** + * Ctor. + * @param elm To repeat + * @param cnt Count + */ + public RepeatIterable(final UncheckedScalar elm, final int cnt) { this.element = elm; this.count = cnt; } diff --git a/src/main/java/org/cactoos/list/RepeatIterator.java b/src/main/java/org/cactoos/list/RepeatIterator.java index 1e8a369217..4d24d8b3b2 100644 --- a/src/main/java/org/cactoos/list/RepeatIterator.java +++ b/src/main/java/org/cactoos/list/RepeatIterator.java @@ -24,6 +24,8 @@ package org.cactoos.list; import java.util.Iterator; +import org.cactoos.Scalar; +import org.cactoos.func.UncheckedScalar; /** * Repeat an element. @@ -41,7 +43,7 @@ public final class RepeatIterator implements Iterator { /** * The element to repeat. */ - private final T element; + private final UncheckedScalar element; /** * How many more repeats will happen. @@ -54,6 +56,24 @@ public final class RepeatIterator implements Iterator { * @param max How many times to repeat */ public RepeatIterator(final T elm, final int max) { + this(() -> elm, max); + } + + /** + * Ctor. + * @param elm Element to repeat + * @param max How many times to repeat + */ + public RepeatIterator(final Scalar elm, final int max) { + this(new UncheckedScalar(elm), max); + } + + /** + * Ctor. + * @param elm Element to repeat + * @param max How many times to repeat + */ + public RepeatIterator(final UncheckedScalar elm, final int max) { this.element = elm; this.left = max; } @@ -66,6 +86,6 @@ public boolean hasNext() { @Override public T next() { --this.left; - return this.element; + return this.element.asValue(); } } diff --git a/src/main/java/org/cactoos/list/SkippedIterable.java b/src/main/java/org/cactoos/list/SkippedIterable.java new file mode 100644 index 0000000000..79c55ef92e --- /dev/null +++ b/src/main/java/org/cactoos/list/SkippedIterable.java @@ -0,0 +1,64 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.list; + +import java.util.Iterator; + +/** + * Skipped iterable. + * + *

There is no thread-safety guarantee.

+ * + * @author Ilia Rogozhin (ilia.rogozhin@gmail.com) + * @version $Id$ + * @param Element type + * @since 0.8 + */ +public final class SkippedIterable implements Iterable { + + /** + * Decorated iterable. + */ + private final Iterable iterable; + + /** + * Count skip elements. + */ + private final int skip; + + /** + * Ctor. + * @param iterable Decorated iterable + * @param skip Count skip elements + */ + public SkippedIterable(final Iterable iterable, final int skip) { + this.iterable = iterable; + this.skip = skip; + } + + @Override + public Iterator iterator() { + return new SkippedIterator<>(this.iterable.iterator(), this.skip); + } +} diff --git a/src/main/java/org/cactoos/list/SkippedIterator.java b/src/main/java/org/cactoos/list/SkippedIterator.java new file mode 100644 index 0000000000..4774f1038e --- /dev/null +++ b/src/main/java/org/cactoos/list/SkippedIterator.java @@ -0,0 +1,77 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.list; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Skipped iterator. + * + *

There is no thread-safety guarantee.

+ * + * @author Ilia Rogozhin (ilia.rogozhin@gmail.com) + * @version $Id$ + * @param Element type + * @since 0.8 + */ +public final class SkippedIterator implements Iterator { + + /** + * Decorated iterator. + */ + private final Iterator iterator; + + /** + * Count skip elements. + */ + private int skip; + + /** + * Ctor. + * @param iterator Decorated iterator + * @param skip Count skip elements + */ + public SkippedIterator(final Iterator iterator, final int skip) { + this.iterator = iterator; + this.skip = skip; + } + + @Override + public boolean hasNext() { + while (this.skip > 0 && this.iterator.hasNext()) { + this.iterator.next(); + --this.skip; + } + return this.iterator.hasNext(); + } + + @Override + public T next() { + if (!this.hasNext()) { + throw new NoSuchElementException(); + } + return this.iterator.next(); + } +} diff --git a/src/main/java/org/cactoos/list/StickyIterable.java b/src/main/java/org/cactoos/list/StickyIterable.java new file mode 100644 index 0000000000..7584a8455f --- /dev/null +++ b/src/main/java/org/cactoos/list/StickyIterable.java @@ -0,0 +1,59 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.list; + +import java.util.Iterator; +import org.cactoos.func.UncheckedScalar; + +/** + * Iterable that returns an iterator only once. + * + *

There is no thread-safety guarantee. + * + * @author Yegor Bugayenko (yegor256@gmail.com) + * @version $Id$ + * @param Type of item + * @since 0.1 + */ +public final class StickyIterable implements Iterable { + + /** + * The cache. + */ + private final UncheckedScalar> cache; + + /** + * Ctor. + * @param iterable The iterable + */ + public StickyIterable(final Iterable iterable) { + this.cache = new UncheckedScalar<>(iterable::iterator); + } + + @Override + public Iterator iterator() { + return this.cache.asValue(); + } + +} diff --git a/src/main/java/org/cactoos/list/StickyList.java b/src/main/java/org/cactoos/list/StickyList.java new file mode 100644 index 0000000000..fe96759d05 --- /dev/null +++ b/src/main/java/org/cactoos/list/StickyList.java @@ -0,0 +1,222 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.list; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import org.cactoos.func.StickyScalar; +import org.cactoos.func.UncheckedScalar; + +/** + * List decorator that goes through the list only once. + * + *

There is no thread-safety guarantee. + * + * @author Yegor Bugayenko (yegor256@gmail.com) + * @version $Id$ + * @param Type of item + * @since 0.8 + */ +@SuppressWarnings("PMD.TooManyMethods") +public final class StickyList implements List { + + /** + * The gate. + */ + private final UncheckedScalar> gate; + + /** + * Ctor. + * @param items The array + */ + @SafeVarargs + @SuppressWarnings("varargs") + public StickyList(final X... items) { + this(new ArrayAsIterable<>(items)); + } + + /** + * Ctor. + * @param items The array + */ + public StickyList(final Iterable items) { + this(new IterableAsList<>(items)); + } + + /** + * Ctor. + * @param list The iterable + */ + public StickyList(final Collection list) { + this.gate = new UncheckedScalar<>( + new StickyScalar<>( + () -> { + final List temp = new LinkedList<>(); + temp.addAll(list); + return temp; + } + ) + ); + } + + @Override + public int size() { + return this.gate.asValue().size(); + } + + @Override + public boolean isEmpty() { + return this.gate.asValue().isEmpty(); + } + + @Override + public boolean contains(final Object object) { + return this.gate.asValue().contains(object); + } + + @Override + public Iterator iterator() { + return this.gate.asValue().iterator(); + } + + @Override + public Object[] toArray() { + return this.gate.asValue().toArray(); + } + + @Override + @SuppressWarnings("PMD.UseVarargs") + public Y[] toArray(final Y[] array) { + return this.gate.asValue().toArray(array); + } + + @Override + public boolean add(final X element) { + throw new UnsupportedOperationException( + "#add(final T element) is not supported" + ); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException( + "#remove(final Object object) is not supported" + ); + } + + @Override + public boolean containsAll(final Collection collection) { + return this.gate.asValue().containsAll(collection); + } + + @Override + public boolean addAll(final Collection collection) { + throw new UnsupportedOperationException( + "#addAll(final Collection collection) is not supported" + ); + } + + @Override + public boolean addAll(final int index, + final Collection collection) { + throw new UnsupportedOperationException( + "#addAll() is not supported" + ); + } + + @Override + public boolean removeAll(final Collection collection) { + throw new UnsupportedOperationException( + "#removeAll(final Collection collection) is not supported" + ); + } + + @Override + public boolean retainAll(final Collection collection) { + throw new UnsupportedOperationException( + "#retainAll(final Collection collection) is not supported" + ); + } + + @Override + public void clear() { + throw new UnsupportedOperationException( + "#clear() is not supported" + ); + } + + @Override + public X get(final int index) { + return this.gate.asValue().get(index); + } + + @Override + public X set(final int index, final X element) { + throw new UnsupportedOperationException( + "#set() is not supported" + ); + } + + @Override + public void add(final int index, final X element) { + throw new UnsupportedOperationException( + "#add(final int index, final T element) is not supported" + ); + } + + @Override + public X remove(final int index) { + throw new UnsupportedOperationException( + "#remove(final int index) is not supported" + ); + } + + @Override + public int indexOf(final Object object) { + return this.gate.asValue().indexOf(object); + } + + @Override + public int lastIndexOf(final Object object) { + return this.gate.asValue().lastIndexOf(object); + } + + @Override + public ListIterator listIterator() { + return this.gate.asValue().listIterator(); + } + + @Override + public ListIterator listIterator(final int index) { + return this.gate.asValue().listIterator(index); + } + + @Override + public List subList(final int fromindex, final int toindex) { + return this.gate.asValue().subList(fromindex, toindex); + } +} diff --git a/src/main/java/org/cactoos/list/StickyMap.java b/src/main/java/org/cactoos/list/StickyMap.java new file mode 100644 index 0000000000..503677ba19 --- /dev/null +++ b/src/main/java/org/cactoos/list/StickyMap.java @@ -0,0 +1,153 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.list; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.cactoos.func.StickyScalar; +import org.cactoos.func.UncheckedScalar; + +/** + * Map decorator that goes through the map only once. + * + *

There is no thread-safety guarantee. + * + * @author Yegor Bugayenko (yegor256@gmail.com) + * @version $Id$ + * @param Type of key + * @param Type of value + * @since 0.8 + */ +public final class StickyMap implements Map { + + /** + * The gate. + */ + private final UncheckedScalar> gate; + + /** + * Ctor. + * @param list List of entries + */ + @SafeVarargs + @SuppressWarnings("varargs") + public StickyMap(final Map.Entry... list) { + this(new ArrayAsIterable<>(list)); + } + + /** + * Ctor. + * @param list Entries for the entries + */ + public StickyMap(final Iterable> list) { + this(new IterableAsMap<>(list)); + } + + /** + * Ctor. + * @param map The map + */ + public StickyMap(final Map map) { + this.gate = new UncheckedScalar<>( + new StickyScalar<>( + () -> { + final Map temp = new HashMap<>(0); + temp.putAll(map); + return temp; + } + ) + ); + } + + @Override + public int size() { + return this.gate.asValue().size(); + } + + @Override + public boolean isEmpty() { + return this.gate.asValue().isEmpty(); + } + + @Override + public boolean containsKey(final Object key) { + return this.gate.asValue().containsKey(key); + } + + @Override + public boolean containsValue(final Object value) { + return this.gate.asValue().containsValue(value); + } + + @Override + public Y get(final Object key) { + return this.gate.asValue().get(key); + } + + @Override + public Y put(final X key, final Y value) { + throw new UnsupportedOperationException( + "#put() is not supported" + ); + } + + @Override + public Y remove(final Object key) { + throw new UnsupportedOperationException( + "#remove() is not supported" + ); + } + + @Override + public void putAll(final Map map) { + throw new UnsupportedOperationException( + "#putAll() is not supported" + ); + } + + @Override + public void clear() { + throw new UnsupportedOperationException( + "#clear() is not supported" + ); + } + + @Override + public Set keySet() { + return this.gate.asValue().keySet(); + } + + @Override + public Collection values() { + return this.gate.asValue().values(); + } + + @Override + public Set> entrySet() { + return this.gate.asValue().entrySet(); + } + +} diff --git a/src/test/java/org/cactoos/func/RetryFunc.java b/src/test/java/org/cactoos/func/RetryFunc.java new file mode 100644 index 0000000000..4ed70018cf --- /dev/null +++ b/src/test/java/org/cactoos/func/RetryFunc.java @@ -0,0 +1,97 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.func; + +import org.cactoos.Func; +import org.cactoos.text.FormattedText; + +/** + * Func that will try a few times before throwing an exception. + * + *

There is no thread-safety guarantee. + * + * @author Yegor Bugayenko (yegor256@gmail.com) + * @version $Id$ + * @param Type of input + * @param Type of output + * @since 0.8 + */ +public final class RetryFunc implements Func { + + /** + * Original func. + */ + private final Func func; + + /** + * Maximum number of attempts to make. + */ + private final int max; + + /** + * Ctor. + * @param fnc Func original + */ + public RetryFunc(final Func fnc) { + // @checkstyle MagicNumberCheck (1 line) + this(fnc, 3); + } + + /** + * Ctor. + * @param fnc Func original + * @param attempts Maximum number of attempts + */ + public RetryFunc(final Func fnc, final int attempts) { + this.func = fnc; + this.max = attempts; + } + + @Override + @SuppressWarnings("PMD.AvoidCatchingGenericException") + public Y apply(final X input) throws Exception { + int attempt = 0; + Exception error = new IllegalArgumentException( + new FormattedText( + "Maximum number of attempts is too small: %d", + this.max + ).asString() + ); + while (attempt < this.max) { + try { + return this.func.apply(input); + } catch (final InterruptedException ex) { + Thread.currentThread().interrupt(); + error = ex; + break; + // @checkstyle IllegalCatchCheck (1 line) + } catch (final Exception ex) { + error = ex; + } + ++attempt; + } + throw error; + } + +} diff --git a/src/test/java/org/cactoos/func/RetryFuncTest.java b/src/test/java/org/cactoos/func/RetryFuncTest.java new file mode 100644 index 0000000000..3afbd601cc --- /dev/null +++ b/src/test/java/org/cactoos/func/RetryFuncTest.java @@ -0,0 +1,58 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.func; + +import java.security.SecureRandom; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Test case for {@link RetryFunc}. + * + * @author Yegor Bugayenko (yegor256@gmail.com) + * @version $Id$ + * @since 0.8 + * @checkstyle JavadocMethodCheck (500 lines) + */ +public final class RetryFuncTest { + + @Test + public void runsFuncMultipleTimes() throws Exception { + MatcherAssert.assertThat( + new RetryFunc<>( + input -> { + // @checkstyle MagicNumberCheck (1 line) + if (new SecureRandom().nextDouble() > 0.3d) { + throw new IllegalArgumentException("May happen"); + } + return 0; + }, + Integer.MAX_VALUE + ).apply(true), + Matchers.equalTo(0) + ); + } + +} diff --git a/src/test/java/org/cactoos/list/IterableAsListTest.java b/src/test/java/org/cactoos/list/IterableAsListTest.java index a0f418d9f8..393b1a1d6a 100644 --- a/src/test/java/org/cactoos/list/IterableAsListTest.java +++ b/src/test/java/org/cactoos/list/IterableAsListTest.java @@ -24,6 +24,8 @@ package org.cactoos.list; import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.Test; @@ -82,4 +84,18 @@ public void highBoundTest() throws Exception { // @checkstyle MagicNumber (1 line) new IterableAsList<>(Collections.nCopies(10, 0)).get(11); } + + @Test + public void sensesChangesInIterable() throws Exception { + final AtomicInteger size = new AtomicInteger(2); + final List list = new IterableAsList<>( + () -> Collections.nCopies(size.incrementAndGet(), 0).iterator() + ); + MatcherAssert.assertThat( + "Can't sense the changes in the underlying iterable", + list.size(), + Matchers.not(Matchers.equalTo(list.size())) + ); + } + } diff --git a/src/test/java/org/cactoos/list/IterableAsMapTest.java b/src/test/java/org/cactoos/list/IterableAsMapTest.java index 5c8ee2b1c0..4f99ff62ce 100644 --- a/src/test/java/org/cactoos/list/IterableAsMapTest.java +++ b/src/test/java/org/cactoos/list/IterableAsMapTest.java @@ -23,7 +23,10 @@ */ package org.cactoos.list; +import java.security.SecureRandom; import java.util.AbstractMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.Test; @@ -52,4 +55,24 @@ public void convertsIterableToMap() { ) ); } + + @Test + public void sensesChangesInMap() throws Exception { + final AtomicInteger size = new AtomicInteger(2); + final Map map = new IterableAsMap<>( + () -> new RepeatIterator<>( + () -> new AbstractMap.SimpleEntry<>( + new SecureRandom().nextInt(), + 1 + ), + size.incrementAndGet() + ) + ); + MatcherAssert.assertThat( + "Can't sense the changes in the underlying map", + map.size(), + Matchers.not(Matchers.equalTo(map.size())) + ); + } + } diff --git a/src/test/java/org/cactoos/list/MapAsPropertiesTest.java b/src/test/java/org/cactoos/list/MapAsPropertiesTest.java index 0b0c9181ee..75cf15409a 100644 --- a/src/test/java/org/cactoos/list/MapAsPropertiesTest.java +++ b/src/test/java/org/cactoos/list/MapAsPropertiesTest.java @@ -23,11 +23,14 @@ */ package org.cactoos.list; +import java.security.SecureRandom; import java.util.AbstractMap; import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; import org.cactoos.ScalarHasValue; import org.cactoos.func.FuncAsMatcher; import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; import org.junit.Test; /** @@ -37,6 +40,7 @@ * @version $Id$ * @since 0.7 * @checkstyle JavadocMethodCheck (500 lines) + * @checkstyle ClassDataAbstractionCouplingCheck (500 lines) */ public final class MapAsPropertiesTest { @@ -45,9 +49,11 @@ public void convertsMapToProperties() { MatcherAssert.assertThat( "Can't convert map to properties", new MapAsProperties( - new IterableAsMap( - new AbstractMap.SimpleEntry<>(0, "hello, world"), - new AbstractMap.SimpleEntry<>(1, "how are you?") + new StickyMap<>( + new IterableAsMap( + new AbstractMap.SimpleEntry<>(0, "hello, world"), + new AbstractMap.SimpleEntry<>(1, "how are you?") + ) ) ), new ScalarHasValue<>( @@ -57,4 +63,26 @@ public void convertsMapToProperties() { ) ); } + + @Test + public void sensesChangesInMap() throws Exception { + final AtomicInteger size = new AtomicInteger(2); + final MapAsProperties props = new MapAsProperties( + new IterableAsMap<>( + () -> new RepeatIterator<>( + () -> new AbstractMap.SimpleEntry<>( + new SecureRandom().nextInt(), + 1 + ), + size.incrementAndGet() + ) + ) + ); + MatcherAssert.assertThat( + "Can't sense the changes in the underlying map", + props.asValue().size(), + Matchers.not(Matchers.equalTo(props.asValue().size())) + ); + } + } diff --git a/src/test/java/org/cactoos/list/SkippedIterableTest.java b/src/test/java/org/cactoos/list/SkippedIterableTest.java new file mode 100644 index 0000000000..be13d8ce58 --- /dev/null +++ b/src/test/java/org/cactoos/list/SkippedIterableTest.java @@ -0,0 +1,57 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.list; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Test Case for {@link SkippedIterable}. + * @author Ilia Rogozhin (ilia.rogozhin@gmail.com) + * @version $Id$ + * @since 0.8 + * @checkstyle JavadocMethodCheck (500 lines) + */ +public final class SkippedIterableTest { + + @Test + @SuppressWarnings("PMD.AvoidDuplicateLiterals") + public void skipIterable() throws Exception { + MatcherAssert.assertThat( + "Can't skip elements in iterable", + new SkippedIterable<>( + new ArrayAsIterable<>( + "one", "two", "three", "four" + ), + 2 + ), + Matchers.contains( + "three", + "four" + ) + ); + } + +} diff --git a/src/test/java/org/cactoos/list/SkippedIteratorTest.java b/src/test/java/org/cactoos/list/SkippedIteratorTest.java new file mode 100644 index 0000000000..1bbd485af6 --- /dev/null +++ b/src/test/java/org/cactoos/list/SkippedIteratorTest.java @@ -0,0 +1,67 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.list; + +import java.util.NoSuchElementException; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Test Case for {@link SkippedIterator}. + * @author Ilia Rogozhin (ilia.rogozhin@gmail.com) + * @version $Id$ + * @since 0.8 + * @checkstyle JavadocMethodCheck (500 lines) + */ +public final class SkippedIteratorTest { + + @Test + @SuppressWarnings("PMD.AvoidDuplicateLiterals") + public void skipIterator() throws Exception { + MatcherAssert.assertThat( + "Can't skip elements in iterator", + () -> new SkippedIterator<>( + new ArrayAsIterable<>( + "one", "two", "three", "four" + ).iterator(), + 2 + ), + Matchers.contains( + "three", + "four" + ) + ); + } + + @Test(expected = NoSuchElementException.class) + public void errorSkippedMoreThanExists() throws Exception { + new SkippedIterator<>( + new ArrayAsIterable<>( + "one", "two" + ).iterator(), + 2 + ).next(); + } +} diff --git a/src/test/java/org/cactoos/list/StickyListTest.java b/src/test/java/org/cactoos/list/StickyListTest.java new file mode 100644 index 0000000000..bca5df73a9 --- /dev/null +++ b/src/test/java/org/cactoos/list/StickyListTest.java @@ -0,0 +1,58 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.list; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Test case for {@link StickyList}. + * + * @author Yegor Bugayenko (yegor256@gmail.com) + * @version $Id$ + * @since 0.8 + * @checkstyle JavadocMethodCheck (500 lines) + */ +public final class StickyListTest { + + @Test + public void ignoresChangesInIterable() throws Exception { + final AtomicInteger size = new AtomicInteger(2); + final List list = new StickyList<>( + new IterableAsList<>( + () -> Collections.nCopies(size.incrementAndGet(), 0).iterator() + ) + ); + MatcherAssert.assertThat( + "Can't ignore the changes in the underlying iterable", + list.size(), + Matchers.equalTo(list.size()) + ); + } + +} diff --git a/src/test/java/org/cactoos/list/StickyMapTest.java b/src/test/java/org/cactoos/list/StickyMapTest.java new file mode 100644 index 0000000000..47198e916b --- /dev/null +++ b/src/test/java/org/cactoos/list/StickyMapTest.java @@ -0,0 +1,65 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.cactoos.list; + +import java.security.SecureRandom; +import java.util.AbstractMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Test case for {@link StickyMap}. + * + * @author Yegor Bugayenko (yegor256@gmail.com) + * @version $Id$ + * @since 0.8 + * @checkstyle JavadocMethodCheck (500 lines) + */ +public final class StickyMapTest { + + @Test + public void ignoresChangesInMap() throws Exception { + final AtomicInteger size = new AtomicInteger(2); + final Map map = new StickyMap<>( + new IterableAsMap<>( + () -> new RepeatIterator<>( + () -> new AbstractMap.SimpleEntry<>( + new SecureRandom().nextInt(), + 1 + ), + size.incrementAndGet() + ) + ) + ); + MatcherAssert.assertThat( + "Can't ignore the changes in the underlying map", + map.size(), + Matchers.equalTo(map.size()) + ); + } + +}