diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TAbstractCollection.java b/classlib/src/main/java/org/teavm/classlib/java/util/TAbstractCollection.java index 8fed83afd..b9ad623fe 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TAbstractCollection.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TAbstractCollection.java @@ -32,7 +32,7 @@ public abstract class TAbstractCollection extends TObject implements TCollect public boolean contains(Object o) { for (TIterator iter = iterator(); iter.hasNext();) { E e = iter.next(); - if (e == null ? o == null : e.equals(o)) { + if (TObjects.equals(e, o)) { return true; } } @@ -76,7 +76,7 @@ public abstract class TAbstractCollection extends TObject implements TCollect public boolean remove(Object o) { for (TIterator iter = iterator(); iter.hasNext();) { E e = iter.next(); - if (e == null ? o == null : e.equals(o)) { + if (TObjects.equals(e, o)) { iter.remove(); return true; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java b/classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java index 9aeaa4f6b..a84b4573b 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java @@ -33,7 +33,7 @@ public abstract class TAbstractList extends TAbstractCollection implements @Override public TIterator iterator() { - return new TIterator() { + return new TIterator<>() { private int index; private int modCount = TAbstractList.this.modCount; private int size = size(); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java b/classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java index 1ce5970ed..d7c47cae0 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java @@ -64,6 +64,16 @@ public class TArrayList extends TAbstractList implements TCloneable, TSeri return array[index]; } + @Override + public E getFirst() { + return get(0); + } + + @Override + public E getLast() { + return get(size - 1); + } + @Override public int size() { return size; @@ -102,6 +112,26 @@ public class TArrayList extends TAbstractList implements TCloneable, TSeri ++modCount; } + @Override + public void addFirst(E element) { + add(0, element); + } + + @Override + public void addLast(E element) { + add(element); + } + + @Override + public E removeFirst() { + return remove(0); + } + + @Override + public E removeLast() { + return remove(size - 1); + } + @Override public E remove(int index) { checkIndex(index); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedList.java b/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedList.java index 2fa25925f..0d13bd1b7 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedList.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedList.java @@ -15,6 +15,12 @@ */ package org.teavm.classlib.java.util; +import java.util.function.Consumer; +import java.util.function.IntFunction; +import java.util.function.Predicate; +import org.teavm.classlib.java.util.function.TUnaryOperator; +import org.teavm.classlib.java.util.stream.TStream; + public class TLinkedList extends TAbstractSequentialList implements TDeque { static class Entry { E item; @@ -275,6 +281,11 @@ public class TLinkedList extends TAbstractSequentialList implements TDeque return new DescendingIterator(); } + @Override + public TLinkedList reversed() { + return new ReversedLinkedList<>(this); + } + private void removeEntry(Entry entry) { if (entry.previous != null) { entry.previous.next = entry.next; @@ -441,4 +452,390 @@ public class TLinkedList extends TAbstractSequentialList implements TDeque currentEntry = null; } } + + private static class ReversedLinkedList extends TLinkedList { + private final TLinkedList list; + private final TReversedList reversed; + + private ReversedLinkedList(TLinkedList list) { + this.list = list; + this.reversed = new TReversedList<>(list); + } + + @Override + public String toString() { + return reversed.toString(); + } + + @Override + public boolean retainAll(TCollection c) { + return reversed.retainAll(c); + } + + @Override + public boolean removeAll(TCollection c) { + return reversed.removeAll(c); + } + + @Override + public boolean containsAll(TCollection c) { + return reversed.containsAll(c); + } + + @Override + public boolean isEmpty() { + return list.isEmpty(); + } + + @Override + public TStream stream() { + return reversed.stream(); + } + + @Override + public boolean removeIf(Predicate filter) { + return list.removeIf(filter); + } + + @Override + public T[] toArray(IntFunction generator) { + return reversed.toArray(generator); + } + + @Override + public void forEach(Consumer action) { + reversed.forEach(action); + } + + @Override + public TIterator iterator() { + return list.descendingIterator(); + } + + @Override + public int hashCode() { + return reversed.hashCode(); + } + + @Override + public boolean equals(Object o) { + return reversed.equals(o); + } + + @Override + public TList subList(int fromIndex, int toIndex) { + return reversed.subList(fromIndex, toIndex); + } + + @Override + public TListIterator listIterator() { + TListIterator lit = list.listIterator(list.size()); + return new TListIterator<>() { + @Override + public boolean hasPrevious() { + return lit.hasNext(); + } + + @Override + public E previous() { + return lit.next(); + } + + @Override + public int nextIndex() { + return list.size() - lit.previousIndex() - 1; + } + + @Override + public int previousIndex() { + return list.size() - lit.nextIndex() - 1; + } + + @Override + public void set(E e) { + lit.set(e); + } + + @Override + public void add(E e) { + lit.add(e); + } + + @Override + public boolean hasNext() { + return lit.hasPrevious(); + } + + @Override + public E next() { + return lit.previous(); + } + + @Override + public void remove() { + lit.remove(); + } + }; + } + + @Override + public void sort(TComparator c) { + reversed.sort(c); + } + + @Override + public void replaceAll(TUnaryOperator operator) { + list.replaceAll(operator); + } + + @Override + public TLinkedList reversed() { + return list; + } + + @Override + public TSpliterator spliterator() { + return reversed.spliterator(); + } + + @Override + public T[] toArray(T[] a) { + return reversed.toArray(a); + } + + @Override + public Object[] toArray() { + return reversed.toArray(); + } + + @Override + public TIterator descendingIterator() { + return list.iterator(); + } + + @Override + public TListIterator listIterator(int index) { + TListIterator lit = list.listIterator(list.size() - index); + return new TListIterator<>() { + @Override + public boolean hasPrevious() { + return lit.hasNext(); + } + + @Override + public E previous() { + return lit.next(); + } + + @Override + public int nextIndex() { + return list.size() - lit.previousIndex() - 1; + } + + @Override + public int previousIndex() { + return list.size() - lit.nextIndex() - 1; + } + + @Override + public void set(E e) { + lit.set(e); + } + + @Override + public void add(E e) { + lit.add(e); + } + + @Override + public boolean hasNext() { + return lit.hasPrevious(); + } + + @Override + public E next() { + return lit.previous(); + } + + @Override + public void remove() { + lit.remove(); + } + }; + } + + @Override + public boolean removeLastOccurrence(Object o) { + return list.removeFirstOccurrence(o); + } + + @Override + public boolean removeFirstOccurrence(Object o) { + return list.removeLastOccurrence(o); + } + + @Override + public E pop() { + return list.removeLast(); + } + + @Override + public void push(E e) { + list.addLast(e); + } + + @Override + public E pollLast() { + return list.pollFirst(); + } + + @Override + public E pollFirst() { + return list.pollLast(); + } + + @Override + public E peekLast() { + return list.peekFirst(); + } + + @Override + public E peekFirst() { + return list.peekLast(); + } + + @Override + public boolean offerLast(E e) { + return list.offerFirst(e); + } + + @Override + public boolean offerFirst(E e) { + return list.offerLast(e); + } + + @Override + public boolean offer(E e) { + return list.offerLast(e); + } + + @Override + public E remove() { + return list.removeFirst(); + } + + @Override + public E poll() { + return list.pollLast(); + } + + @Override + public E element() { + if (list.lastEntry == null) { + throw new TNoSuchElementException(); + } + return list.lastEntry.item; + } + + @Override + public E peek() { + return list.lastEntry != null ? list.lastEntry.item : null; + } + + @Override + public int lastIndexOf(Object o) { + return list.size() - list.indexOf(o) - 1; + } + + @Override + public int indexOf(Object o) { + return list.size() - list.lastIndexOf(o) - 1; + } + + @Override + public E remove(int index) { + return reversed.remove(index); + } + + @Override + public void add(int index, E element) { + reversed.add(index, element); + } + + @Override + public E set(int index, E element) { + return reversed.set(index, element); + } + + @Override + public E get(int index) { + return reversed.get(index); + } + + @Override + public void clear() { + list.clear(); + } + + @Override + public boolean addAll(int index, TCollection c) { + return reversed.addAll(index, c); + } + + @Override + public boolean addAll(TCollection c) { + return reversed.addAll(c); + } + + @Override + public boolean remove(Object o) { + return list.removeLastOccurrence(o); + } + + @Override + public boolean add(E e) { + list.addLast(e); + return true; + } + + @Override + public int size() { + return list.size(); + } + + @Override + public boolean contains(Object o) { + return list.contains(o); + } + + @Override + public void addLast(E e) { + list.addFirst(e); + } + + @Override + public void addFirst(E e) { + list.addLast(e); + } + + @Override + public E removeLast() { + return list.removeFirst(); + } + + @Override + public E removeFirst() { + return list.removeLast(); + } + + @Override + public E getLast() { + return list.getFirst(); + } + + @Override + public E getFirst() { + return list.getLast(); + } + } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TList.java b/classlib/src/main/java/org/teavm/classlib/java/util/TList.java index 04a2f886c..8b2076ac9 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TList.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TList.java @@ -18,7 +18,7 @@ package org.teavm.classlib.java.util; import java.util.Objects; import org.teavm.classlib.java.util.function.TUnaryOperator; -public interface TList extends TCollection { +public interface TList extends TSequencedCollection { boolean addAll(int index, TCollection c); E get(int index); @@ -50,6 +50,54 @@ public interface TList extends TCollection { TCollections.sort(this, c); } + @Override + default void addFirst(E e) { + add(0, e); + } + + @Override + default void addLast(E e) { + add(e); + } + + @Override + default E getFirst() { + if (isEmpty()) { + throw new TNoSuchElementException(); + } + return get(0); + } + + @Override + default E getLast() { + if (isEmpty()) { + throw new TNoSuchElementException(); + } + return get(this.size() - 1); + } + + @Override + default E removeFirst() { + if (isEmpty()) { + throw new TNoSuchElementException(); + } + return remove(0); + } + + @Override + default E removeLast() { + if (isEmpty()) { + throw new TNoSuchElementException(); + } + return remove(this.size() - 1); + } + + @Override + default TList reversed() { + return this instanceof TRandomAccess ? new TReversedList.RandomAccess<>(this) + : new TReversedList<>(this); + } + static TList of() { return TCollections.emptyList(); } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TReversedList.java b/classlib/src/main/java/org/teavm/classlib/java/util/TReversedList.java new file mode 100644 index 000000000..1f7364a20 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TReversedList.java @@ -0,0 +1,121 @@ +/* + * Copyright 2023 ihromant. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.java.util; + +class TReversedList extends TAbstractList { + private final TList base; + + TReversedList(TList base) { + this.base = base; + } + + @Override + public E get(int index) { + return base.get(size() - index - 1); + } + + @Override + public int size() { + return base.size(); + } + + @Override + public E set(int index, E element) { + return base.set(size() - index - 1, element); + } + + @Override + public void add(int index, E element) { + base.add(size() - index, element); + } + + @Override + public E remove(int index) { + return base.remove(size() - index - 1); + } + + @Override + public void addFirst(E element) { + base.addLast(element); + } + + @Override + public void addLast(E element) { + base.addFirst(element); + } + + @Override + public E removeFirst() { + return base.remove(size() - 1); + } + + @Override + public E removeLast() { + return base.remove(0); + } + + @Override + public E getFirst() { + return base.getLast(); + } + + @Override + public E getLast() { + return base.getFirst(); + } + + @Override + public TIterator iterator() { + TListIterator lit = base.listIterator(size()); + return new TIterator<>() { + @Override + public boolean hasNext() { + return lit.hasPrevious(); + } + + @Override + public E next() { + return lit.previous(); + } + + @Override + public void remove() { + lit.remove(); + } + }; + } + + @Override + public void clear() { + base.clear(); + } + + @Override + public boolean contains(Object o) { + return base.contains(o); + } + + @Override + public TList reversed() { + return base; + } + + static class RandomAccess extends TReversedList implements TRandomAccess { + RandomAccess(TList base) { + super(base); + } + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TSequencedCollection.java b/classlib/src/main/java/org/teavm/classlib/java/util/TSequencedCollection.java new file mode 100644 index 000000000..0878a42d0 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TSequencedCollection.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023 ihromant. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.java.util; + +public interface TSequencedCollection extends TCollection { + + TSequencedCollection reversed(); + + default void addFirst(E e) { + throw new UnsupportedOperationException(); + } + + default void addLast(E e) { + throw new UnsupportedOperationException(); + } + + default E getFirst() { + return this.iterator().next(); + } + + default E getLast() { + return this.reversed().iterator().next(); + } + + default E removeFirst() { + var it = this.iterator(); + E e = it.next(); + it.remove(); + return e; + } + + default E removeLast() { + var it = this.reversed().iterator(); + E e = it.next(); + it.remove(); + return e; + } +} + diff --git a/tests/src/test/java/org/teavm/classlib/java/util/ArrayListTest.java b/tests/src/test/java/org/teavm/classlib/java/util/ArrayListTest.java index 76dea2d9c..5373ad02e 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/ArrayListTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/ArrayListTest.java @@ -16,19 +16,26 @@ package org.teavm.classlib.java.util; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.ConcurrentModificationException; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; import org.junit.Test; import org.junit.runner.RunWith; import org.teavm.junit.TeaVMTestRunner; +import org.teavm.junit.WholeClassCompilation; @RunWith(TeaVMTestRunner.class) +@WholeClassCompilation public class ArrayListTest { @Test public void elementsAdded() { @@ -208,4 +215,79 @@ public class ArrayListTest { assertEquals(new LinkedList<>(Arrays.asList(1, 3, null, 2)), new ArrayList<>(Arrays.asList(1, 3, null, 2))); assertNotEquals(new ArrayList<>(Arrays.asList(1, 3, 2)), new ArrayList<>(Arrays.asList(1, 3, null, 2))); } + + @Test + public void testSequencedCollectionReadOnly() { + List list = new ArrayList<>(List.of("0", "1", "2", "3", "4", "5", "6")); + List reversed = list.reversed(); + assertEquals("1", reversed.get(5)); + Iterator it = reversed.iterator(); + assertEquals("6", it.next()); + assertEquals("5", it.next()); + assertEquals("6", reversed.getFirst()); + assertEquals("0", reversed.getLast()); + ListIterator lit = reversed.listIterator(); + assertFalse(lit.hasPrevious()); + assertTrue(lit.hasNext()); + assertEquals("6", lit.next()); + assertEquals("5", lit.next()); + assertEquals("5", lit.previous()); + lit = reversed.listIterator(2); + assertEquals("4", lit.next()); + lit.previous(); + assertEquals("5", lit.previous()); + assertSame(list, reversed.reversed()); + List subList = reversed.subList(3, 5); + assertEquals("2", subList.getLast()); + assertEquals("3", subList.listIterator().next()); + StringBuilder sb = new StringBuilder(); + subList.forEach(sb::append); + assertEquals("32", sb.toString()); + List duplicates = new ArrayList<>(List.of(0, 1, 2, 3, 2, 1, 0, 0)).reversed(); + assertEquals(2, duplicates.indexOf(1)); + assertEquals(6, duplicates.lastIndexOf(1)); + } + + @Test + public void testSequencedCollectionMutations() { + List list = new ArrayList<>(List.of("a", "b", "c", "d")); + assertEquals("a", list.removeFirst()); + assertEquals("d", list.removeLast()); + list.addFirst("u"); + list.addLast("e"); + assertEquals(List.of("u", "b", "c", "e"), list); + list = new ArrayList<>(List.of("a", "b", "c", "d")).reversed(); + assertEquals("d", list.removeFirst()); + assertEquals("a", list.removeLast()); + list.addFirst("u"); + list.addLast("e"); + assertEquals("c", list.remove(1)); + list.add(2, "f"); + list.set(1, "k"); + assertEquals(List.of("u", "k", "f", "e"), list); + } + + @Test + public void testSequencedCollectionIterator() { + List list = new ArrayList<>(List.of("a", "b", "c", "d")).reversed(); + Iterator it = list.iterator(); + assertEquals("d", it.next()); + assertEquals("c", it.next()); + it.remove(); + assertEquals(List.of("d", "b", "a"), list); + list = new ArrayList<>(List.of("a", "b", "c", "d")).reversed(); + ListIterator lit = list.listIterator(); + assertEquals("d", lit.next()); + assertEquals("c", lit.next()); + assertEquals("b", lit.next()); + lit.remove(); + assertEquals("c", lit.previous()); + assertEquals(0, lit.previousIndex()); + assertEquals(1, lit.nextIndex()); + lit.remove(); + assertEquals(0, lit.previousIndex()); + assertEquals(1, lit.nextIndex()); + lit.add("x"); + assertEquals(List.of("d", "x", "a"), list); + } } diff --git a/tests/src/test/java/org/teavm/classlib/java/util/LinkedListTest.java b/tests/src/test/java/org/teavm/classlib/java/util/LinkedListTest.java index 7363862f9..ffc3a2c39 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/LinkedListTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/LinkedListTest.java @@ -18,10 +18,12 @@ package org.teavm.classlib.java.util; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import org.junit.Test; @@ -233,4 +235,79 @@ public class LinkedListTest { list.push("bar"); assertEquals("bar", list.peek()); } + + @Test + public void testSequencedCollectionReadOnly() { + List list = new LinkedList<>(List.of("0", "1", "2", "3", "4", "5", "6")); + List reversed = list.reversed(); + assertEquals("1", reversed.get(5)); + Iterator it = reversed.iterator(); + assertEquals("6", it.next()); + assertEquals("5", it.next()); + assertEquals("6", reversed.getFirst()); + assertEquals("0", reversed.getLast()); + ListIterator lit = reversed.listIterator(); + assertFalse(lit.hasPrevious()); + assertTrue(lit.hasNext()); + assertEquals("6", lit.next()); + assertEquals("5", lit.next()); + assertEquals("5", lit.previous()); + lit = reversed.listIterator(2); + assertEquals("4", lit.next()); + lit.previous(); + assertEquals("5", lit.previous()); + assertSame(list, reversed.reversed()); + List subList = reversed.subList(3, 5); + assertEquals("2", subList.getLast()); + assertEquals("3", subList.listIterator().next()); + StringBuilder sb = new StringBuilder(); + subList.forEach(sb::append); + assertEquals("32", sb.toString()); + List duplicates = new LinkedList<>(List.of(0, 1, 2, 3, 2, 1, 0, 0)).reversed(); + assertEquals(2, duplicates.indexOf(1)); + assertEquals(6, duplicates.lastIndexOf(1)); + } + + @Test + public void testSequencedCollectionMutations() { + List list = new LinkedList<>(List.of("a", "b", "c", "d")); + assertEquals("a", list.removeFirst()); + assertEquals("d", list.removeLast()); + list.addFirst("u"); + list.addLast("e"); + assertEquals(List.of("u", "b", "c", "e"), list); + list = new LinkedList<>(List.of("a", "b", "c", "d")).reversed(); + assertEquals("d", list.removeFirst()); + assertEquals("a", list.removeLast()); + list.addFirst("u"); + list.addLast("e"); + assertEquals("c", list.remove(1)); + list.add(2, "f"); + list.set(1, "k"); + assertEquals(List.of("u", "k", "f", "e"), list); + } + + @Test + public void testSequencedCollectionIterator() { + List list = new LinkedList<>(List.of("a", "b", "c", "d")).reversed(); + Iterator it = list.iterator(); + assertEquals("d", it.next()); + assertEquals("c", it.next()); + it.remove(); + assertEquals(List.of("d", "b", "a"), list); + list = new LinkedList<>(List.of("a", "b", "c", "d")).reversed(); + ListIterator lit = list.listIterator(); + assertEquals("d", lit.next()); + assertEquals("c", lit.next()); + assertEquals("b", lit.next()); + lit.remove(); + assertEquals("c", lit.previous()); + assertEquals(0, lit.previousIndex()); + assertEquals(1, lit.nextIndex()); + lit.remove(); + assertEquals(0, lit.previousIndex()); + assertEquals(1, lit.nextIndex()); + lit.add("x"); + assertEquals(List.of("d", "x", "a"), list); + } } diff --git a/tests/src/test/java/org/teavm/classlib/java/util/ListTest.java b/tests/src/test/java/org/teavm/classlib/java/util/ListTest.java index f9d6587c3..6e6185c43 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/ListTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/ListTest.java @@ -17,11 +17,14 @@ package org.teavm.classlib.java.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import org.junit.Test; import org.junit.runner.RunWith; import org.teavm.junit.TeaVMTestRunner; @@ -131,4 +134,48 @@ public class ListTest { assertEquals("isEmpty works properly", expected.length == 0, actual.isEmpty()); } + + @Test + public void testSequencedCollection() { + List list = List.of("0", "1", "2", "3", "4", "5", "6"); + List reversed = list.reversed(); + assertEquals("1", reversed.get(5)); + Iterator it = reversed.iterator(); + assertEquals("6", it.next()); + assertEquals("5", it.next()); + assertEquals("6", reversed.getFirst()); + assertEquals("0", reversed.getLast()); + ListIterator lit = reversed.listIterator(); + assertFalse(lit.hasPrevious()); + assertTrue(lit.hasNext()); + assertEquals("6", lit.next()); + assertEquals("5", lit.next()); + assertEquals("5", lit.previous()); + lit = reversed.listIterator(2); + assertEquals("4", lit.next()); + lit.previous(); + assertEquals("5", lit.previous()); + assertSame(list, reversed.reversed()); + List subList = reversed.subList(3, 5); + assertEquals("2", subList.getLast()); + assertEquals("3", subList.listIterator().next()); + StringBuilder sb = new StringBuilder(); + subList.forEach(sb::append); + assertEquals("32", sb.toString()); + List duplicates = List.of(0, 1, 2, 3, 2, 1, 0, 0).reversed(); + assertEquals(2, duplicates.indexOf(1)); + assertEquals(6, duplicates.lastIndexOf(1)); + try { + list.removeFirst(); + fail(); + } catch (UnsupportedOperationException e) { + // ok + } + try { + reversed.removeLast(); + fail(); + } catch (UnsupportedOperationException e) { + // ok + } + } }