8358015: Fix SequencedMap sequenced view method specifications

Reviewed-by: jpai, bchristi
This commit is contained in:
Stuart Marks 2025-06-04 16:14:31 +00:00
parent c909216446
commit ef47635d5a
3 changed files with 71 additions and 12 deletions

View File

@ -877,6 +877,14 @@ public abstract class AbstractMap<K,V> implements Map<K,V> {
*/
/* non-public */ abstract static class ViewCollection<E> implements Collection<E> {
UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
// convert null entry return values into NSEE
static <T extends Map.Entry<?,?>> T nsee(T entry) {
if (entry == null) {
throw new NoSuchElementException();
} else {
return entry;
}
}
abstract Collection<E> view();
public boolean add(E t) { throw uoe(); }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2025, 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
@ -263,8 +263,15 @@ public interface SequencedMap<K, V> extends Map<K, V> {
*
* @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}.
* that behaves as follows. Its {@link SequencedSet#add add}, {@link
* SequencedSet#addAll addAll}, {@link SequencedSet#addFirst addFirst}, and {@link
* SequencedSet#addLast addLast} methods throw {@link UnsupportedOperationException}.
* Its {@link SequencedSet#getFirst getFirst} and {@link SequencedSet#getLast getLast}
* methods are implemented in terms of the {@link #firstEntry firstEntry} and {@link
* #lastEntry lastEntry} methods of this interface, respectively. Its {@link
* SequencedSet#removeFirst removeFirst} and {@link SequencedSet#removeLast removeLast}
* methods are implemented in terms of the {@link #pollFirstEntry pollFirstEntry} and
* {@link #pollLastEntry pollLastEntry} methods of this interface, respectively.
* 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
@ -286,6 +293,16 @@ public interface SequencedMap<K, V> extends Map<K, V> {
public int hashCode() {
return view().hashCode();
}
public void addFirst(K k) { throw new UnsupportedOperationException(); }
public void addLast(K k) { throw new UnsupportedOperationException(); }
public K getFirst() { return nsee(SequencedMap.this.firstEntry()).getKey(); }
public K getLast() { return nsee(SequencedMap.this.lastEntry()).getKey(); }
public K removeFirst() {
return nsee(SequencedMap.this.pollFirstEntry()).getKey();
}
public K removeLast() {
return nsee(SequencedMap.this.pollLastEntry()).getKey();
}
}
return new SeqKeySet();
}
@ -295,8 +312,15 @@ public interface SequencedMap<K, V> extends Map<K, V> {
*
* @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}.
* that behaves as follows. Its {@link SequencedCollection#add add}, {@link
* SequencedCollection#addAll addAll}, {@link SequencedCollection#addFirst addFirst}, and {@link
* SequencedCollection#addLast addLast} methods throw {@link UnsupportedOperationException}.
* Its {@link SequencedCollection#getFirst getFirst} and {@link SequencedCollection#getLast getLast}
* methods are implemented in terms of the {@link #firstEntry firstEntry} and {@link
* #lastEntry lastEntry} methods of this interface, respectively. Its {@link
* SequencedCollection#removeFirst removeFirst} and {@link SequencedCollection#removeLast removeLast}
* methods are implemented in terms of the {@link #pollFirstEntry pollFirstEntry} and
* {@link #pollLastEntry pollLastEntry} methods of this interface, respectively.
* 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
@ -313,6 +337,16 @@ public interface SequencedMap<K, V> extends Map<K, V> {
public SequencedCollection<V> reversed() {
return SequencedMap.this.reversed().sequencedValues();
}
public void addFirst(V v) { throw new UnsupportedOperationException(); }
public void addLast(V v) { throw new UnsupportedOperationException(); }
public V getFirst() { return nsee(SequencedMap.this.firstEntry()).getValue(); }
public V getLast() { return nsee(SequencedMap.this.lastEntry()).getValue(); }
public V removeFirst() {
return nsee(SequencedMap.this.pollFirstEntry()).getValue();
}
public V removeLast() {
return nsee(SequencedMap.this.pollLastEntry()).getValue();
}
}
return new SeqValues();
}
@ -322,8 +356,15 @@ public interface SequencedMap<K, V> extends Map<K, V> {
*
* @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}.
* that behaves as follows. Its {@link SequencedSet#add add}, {@link
* SequencedSet#addAll addAll}, {@link SequencedSet#addFirst addFirst}, and {@link
* SequencedSet#addLast addLast} methods throw {@link UnsupportedOperationException}.
* Its {@link SequencedSet#getFirst getFirst} and {@link SequencedSet#getLast getLast}
* methods are implemented in terms of the {@link #firstEntry firstEntry} and {@link
* #lastEntry lastEntry} methods of this interface, respectively. Its {@link
* SequencedSet#removeFirst removeFirst} and {@link SequencedSet#removeLast removeLast}
* methods are implemented in terms of the {@link #pollFirstEntry pollFirstEntry} and
* {@link #pollLastEntry pollLastEntry} methods of this interface, respectively.
* 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
@ -346,6 +387,16 @@ public interface SequencedMap<K, V> extends Map<K, V> {
public int hashCode() {
return view().hashCode();
}
public void addFirst(Map.Entry<K, V> e) { throw new UnsupportedOperationException(); }
public void addLast(Map.Entry<K, V> e) { throw new UnsupportedOperationException(); }
public Map.Entry<K, V> getFirst() { return nsee(SequencedMap.this.firstEntry()); }
public Map.Entry<K, V> getLast() { return nsee(SequencedMap.this.lastEntry()); }
public Map.Entry<K, V> removeFirst() {
return nsee(SequencedMap.this.pollFirstEntry());
}
public Map.Entry<K, V> removeLast() {
return nsee(SequencedMap.this.pollLastEntry());
}
}
return new SeqEntrySet();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, 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
@ -563,12 +563,12 @@ public class BasicMap {
SequencedMap<Object, Object> objMap = (SequencedMap<Object, Object>)(SequencedMap)map;
assertThrows(CCE, () -> { objMap.put(new Object(), 99); });
assertThrows(CCE, () -> { objMap.put("x", new Object()); });
assertThrows(CCE, () -> { objMap.sequencedEntrySet().getFirst().setValue(new Object()); });
assertThrows(CCE, () -> { objMap.sequencedEntrySet().reversed().getFirst().setValue(new Object()); });
assertThrows(CCE, () -> { objMap.sequencedEntrySet().iterator().next().setValue(new Object()); });
assertThrows(CCE, () -> { objMap.sequencedEntrySet().reversed().iterator().next().setValue(new Object()); });
assertThrows(CCE, () -> { objMap.reversed().put(new Object(), 99); });
assertThrows(CCE, () -> { objMap.reversed().put("x", new Object()); });
assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().getFirst().setValue(new Object()); });
assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().reversed().getFirst().setValue(new Object()); });
assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().iterator().next().setValue(new Object()); });
assertThrows(CCE, () -> { objMap.reversed().sequencedEntrySet().reversed().iterator().next().setValue(new Object()); });
}
public void checkEntry(Map.Entry<String, Integer> entry, String key, Integer value) {