/* * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util; import jdk.internal.util.NullableKeyValueHolder; /** * A Map that has a well-defined encounter order, that supports operations at both ends, and * that is reversible. The encounter order * of a {@code SequencedMap} is similar to that of the elements of a {@link SequencedCollection}, * but the ordering applies to mappings instead of individual elements. *

* The bulk operations on this map, including the {@link #forEach forEach} and the * {@link #replaceAll replaceAll} methods, operate on this map's mappings in * encounter order. *

* The view collections provided by the * {@link #keySet keySet}, * {@link #values values}, * {@link #entrySet entrySet}, * {@link #sequencedKeySet sequencedKeySet}, * {@link #sequencedValues sequencedValues}, * and * {@link #sequencedEntrySet sequencedEntrySet} methods all reflect the encounter order * of this map. Even though the return values of the {@code keySet}, {@code values}, and * {@code entrySet} methods are not sequenced types, the elements * in those view collections do reflect the encounter order of this map. Thus, the * iterators returned by the statements * {@snippet : * var it1 = sequencedMap.entrySet().iterator(); * var it2 = sequencedMap.sequencedEntrySet().iterator(); * } * both provide the mappings of {@code sequencedMap} in that map's encounter order. *

* This interface provides methods to add mappings, to retrieve mappings, and to remove * mappings at either end of the map's encounter order. *

* This interface also defines the {@link #reversed} method, which provides a * reverse-ordered view of this map. * In the reverse-ordered view, the concepts of first and last are inverted, as * are the concepts of successor and predecessor. The first mapping of this map * is the last mapping of the reverse-ordered view, and vice-versa. The successor of some * mapping in this map is its predecessor in the reversed view, and vice-versa. All * methods that respect the encounter order of the map operate as if the encounter order * is inverted. For instance, the {@link #forEach forEach} method of the reversed view reports * the mappings in order from the last mapping of this map to the first. In addition, all of * the view collections of the reversed view also reflect the inverse of this map's * encounter order. For example, * {@snippet : * var itr = sequencedMap.reversed().entrySet().iterator(); * } * provides the mappings of this map in the inverse of the encounter order, that is, from * the last mapping to the first mapping. The availability of the {@code reversed} method, * and its impact on the ordering semantics of all applicable methods and views, allow convenient * iteration, searching, copying, and streaming of this map's mappings in either forward order or * reverse order. *

* A map's reverse-ordered view is generally not serializable, even if the original * map is serializable. *

* The {@link Map.Entry} instances obtained by iterating the {@link #entrySet} view, the * {@link #sequencedEntrySet} view, and its reverse-ordered view, maintain a connection to the * underlying map. This connection is guaranteed only during the iteration. It is unspecified * whether the connection is maintained outside of the iteration. If the underlying map permits * it, calling an Entry's {@link Map.Entry#setValue setValue} method will modify the value of the * underlying mapping. It is, however, unspecified whether modifications to the value in the * underlying mapping are visible in the {@code Entry} instance. *

* The methods * {@link #firstEntry}, * {@link #lastEntry}, * {@link #pollFirstEntry}, and * {@link #pollLastEntry} * return {@link Map.Entry} instances that represent snapshots of mappings as * of the time of the call. They do not support mutation of the * underlying map via the optional {@link Map.Entry#setValue setValue} method. *

* Depending upon the implementation, the {@code Entry} instances returned by other * means might or might not be connected to the underlying map. For example, consider * an {@code Entry} obtained in the following manner: * {@snippet : * var entry = sequencedMap.sequencedEntrySet().getFirst(); * } * It is not specified by this interface whether the {@code setValue} method of the * {@code Entry} thus obtained will update a mapping in the underlying map, or whether * it will throw an exception, or whether changes to the underlying map are visible in * that {@code Entry}. *

* This interface has the same requirements on the {@code equals} and {@code hashCode} * methods as defined by {@link Map#equals Map.equals} and {@link Map#hashCode Map.hashCode}. * Thus, a {@code Map} and a {@code SequencedMap} will compare equals if and only * if they have equal mappings, irrespective of ordering. *

* This class is a member of the * * Java Collections Framework. * * @param the type of keys maintained by this map * @param the type of mapped values * @since 21 */ public interface SequencedMap extends Map { /** * Returns a reverse-ordered view of this map. * The encounter order of mappings in the returned view is the inverse of the encounter * order of mappings in this map. The reverse ordering affects all order-sensitive operations, * including those on the view collections of the returned view. If the implementation permits * modifications to this view, the modifications "write through" to the underlying map. * Changes to the underlying map might or might not be visible in this reversed view, * depending upon the implementation. * * @return a reverse-ordered view of this map */ SequencedMap reversed(); /** * Returns the first key-value mapping in this map, * or {@code null} if the map is empty. * * @implSpec * The implementation in this interface obtains the iterator of this map's entrySet. * If the iterator has an element, it returns an unmodifiable copy of that element. * Otherwise, it returns null. * * @return the first key-value mapping, * or {@code null} if this map is empty */ default Map.Entry firstEntry() { var it = entrySet().iterator(); return it.hasNext() ? new NullableKeyValueHolder<>(it.next()) : null; } /** * Returns the last key-value mapping in this map, * or {@code null} if the map is empty. * * @implSpec * The implementation in this interface obtains the iterator of the entrySet of this map's * reversed view. If the iterator has an element, it returns an unmodifiable copy of * that element. Otherwise, it returns null. * * @return the last key-value mapping, * or {@code null} if this map is empty */ default Map.Entry lastEntry() { var it = reversed().entrySet().iterator(); return it.hasNext() ? new NullableKeyValueHolder<>(it.next()) : null; } /** * Removes and returns the first key-value mapping in this map, * or {@code null} if the map is empty (optional operation). * * @implSpec * The implementation in this interface obtains the iterator of this map's entrySet. * If the iterator has an element, it calls {@code remove} on the iterator and * then returns an unmodifiable copy of that element. Otherwise, it returns null. * * @return the removed first entry of this map, * or {@code null} if this map is empty * @throws UnsupportedOperationException if this collection implementation does not * support this operation */ default Map.Entry pollFirstEntry() { var it = entrySet().iterator(); if (it.hasNext()) { var entry = new NullableKeyValueHolder<>(it.next()); it.remove(); return entry; } else { return null; } } /** * Removes and returns the last key-value mapping in this map, * or {@code null} if the map is empty (optional operation). * * @implSpec * The implementation in this interface obtains the iterator of the entrySet of this map's * reversed view. If the iterator has an element, it calls {@code remove} on the iterator * and then returns an unmodifiable copy of that element. Otherwise, it returns null. * * @return the removed last entry of this map, * or {@code null} if this map is empty * @throws UnsupportedOperationException if this collection implementation does not * support this operation */ default Map.Entry pollLastEntry() { var it = reversed().entrySet().iterator(); if (it.hasNext()) { var entry = new NullableKeyValueHolder<>(it.next()); it.remove(); return entry; } else { return null; } } /** * Inserts the given mapping into the map if it is not already present, or replaces the * value of a mapping if it is already present (optional operation). After this operation * completes normally, the given mapping will be present in this map, and it will be the * first mapping in this map's encounter order. * * @implSpec The implementation in this interface always throws * {@code UnsupportedOperationException}. * * @param k the key * @param v the value * @return the value previously associated with k, or null if none * @throws UnsupportedOperationException if this collection implementation does not * support this operation */ default V putFirst(K k, V v) { throw new UnsupportedOperationException(); } /** * Inserts the given mapping into the map if it is not already present, or replaces the * value of a mapping if it is already present (optional operation). After this operation * completes normally, the given mapping will be present in this map, and it will be the * last mapping in this map's encounter order. * * @implSpec The implementation in this interface always throws * {@code UnsupportedOperationException}. * * @param k the key * @param v the value * @return the value previously associated with k, or null if none * @throws UnsupportedOperationException if this collection implementation does not * support this operation */ default V putLast(K k, V v) { throw new UnsupportedOperationException(); } /** * Returns a {@code SequencedSet} view of this map's {@link #keySet keySet}. * * @implSpec * The implementation in this interface returns a {@code SequencedSet} instance * that behaves as follows. Its {@link SequencedSet#add add} and {@link * SequencedSet#addAll addAll} methods throw {@link UnsupportedOperationException}. * Its {@link SequencedSet#reversed reversed} method returns the {@link * #sequencedKeySet sequencedKeySet} view of the {@link #reversed reversed} view of * this map. Each of its other methods calls the corresponding method of the {@link * #keySet keySet} view of this map. * * @return a {@code SequencedSet} view of this map's {@code keySet} */ default SequencedSet sequencedKeySet() { class SeqKeySet extends AbstractMap.ViewCollection implements SequencedSet { Collection view() { return SequencedMap.this.keySet(); } public SequencedSet reversed() { return SequencedMap.this.reversed().sequencedKeySet(); } public boolean equals(Object other) { return view().equals(other); } public int hashCode() { return view().hashCode(); } } return new SeqKeySet(); } /** * Returns a {@code SequencedCollection} view of this map's {@link #values values} collection. * * @implSpec * The implementation in this interface returns a {@code SequencedCollection} instance * that behaves as follows. Its {@link SequencedCollection#add add} and {@link * SequencedCollection#addAll addAll} methods throw {@link UnsupportedOperationException}. * Its {@link SequencedCollection#reversed reversed} method returns the {@link * #sequencedValues sequencedValues} view of the {@link #reversed reversed} view of * this map. Its {@link Object#equals equals} and {@link Object#hashCode hashCode} methods * are inherited from {@link Object}. Each of its other methods calls the corresponding * method of the {@link #values values} view of this map. * * @return a {@code SequencedCollection} view of this map's {@code values} collection */ default SequencedCollection sequencedValues() { class SeqValues extends AbstractMap.ViewCollection implements SequencedCollection { Collection view() { return SequencedMap.this.values(); } public SequencedCollection reversed() { return SequencedMap.this.reversed().sequencedValues(); } } return new SeqValues(); } /** * Returns a {@code SequencedSet} view of this map's {@link #entrySet entrySet}. * * @implSpec * The implementation in this interface returns a {@code SequencedSet} instance * that behaves as follows. Its {@link SequencedSet#add add} and {@link * SequencedSet#addAll addAll} methods throw {@link UnsupportedOperationException}. * Its {@link SequencedSet#reversed reversed} method returns the {@link * #sequencedEntrySet sequencedEntrySet} view of the {@link #reversed reversed} view of * this map. Each of its other methods calls the corresponding method of the {@link * #entrySet entrySet} view of this map. * * @return a {@code SequencedSet} view of this map's {@code entrySet} */ default SequencedSet> sequencedEntrySet() { class SeqEntrySet extends AbstractMap.ViewCollection> implements SequencedSet> { Collection> view() { return SequencedMap.this.entrySet(); } public SequencedSet> reversed() { return SequencedMap.this.reversed().sequencedEntrySet(); } public boolean equals(Object other) { return view().equals(other); } public int hashCode() { return view().hashCode(); } } return new SeqEntrySet(); } }