abstract static class AbstractImmutableCollection<E> extends AbstractCollection<E> {
// all mutating methods throw UnsupportedOperationException
@Override
public boolean add(E e) {
throw uoe();
}
@Override
public boolean addAll(Collection<? extends E> c) {
throw uoe();
}
@Override
public void clear() {
throw uoe();
}
@Override
public boolean remove(Object o) {
throw uoe();
}
@Override
public boolean removeAll(Collection<?> c) {
throw uoe();
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw uoe();
}
@Override
public boolean retainAll(Collection<?> c) {
throw uoe();
}
}
An unmodifiable collection is a collection, all of whose mutator methods (as defined above) are
specified to throw UnsupportedOperationException. Such a collection thus cannot be modified by
calling any methods on it. For a collection to be properly unmodifiable, any view collections
derived from it must also be unmodifiable.
ImmutableCollections 라고도 불리는 불변 컬렉션은 정의대로 모든 변경자 메소드를 예외를 던지는 상태로 정의되어 있다.
그러므로 이러한 컬렉션은 변경자 메소드를 호출하여 변경할 수 없다. 이러한 컬렉션이 제대로 불변이면 불변 컬렉션으로 부터 부터 상속된 모든 뷰 컬렉션도 불변이다.
List.subLsit
도 불변임 ㅋㅋ
List.of
팩토리 메소드를 이용하여 리스트를 만들 수 있다.
public interface List<E> extends Collection<E> {
// 10개 까지는 이렇게 생김
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
e6, e7, e8, e9, e10);
}
// 10개 이상의 요소를 가진 리스트를 만들 경우
static <E> List<E> of(E... elements) {
switch (elements.length) { // implicit null check of elements
case 0:
@SuppressWarnings("unchecked")
var list = (List<E>) ImmutableCollections.EMPTY_LIST;
return list;
case 1:
return new ImmutableCollections.List12<>(elements[0]);
case 2:
return new ImmutableCollections.List12<>(elements[0], elements[1]);
default:
return ImmutableCollections.listFromArray(elements);
}
}
// null 요소를 금지함
List12(E e0) {
this.e0 = Objects.requireNonNull(e0);
// Use EMPTY as a sentinel for an unused element: not using null
// enables constant folding optimizations over single-element lists
this.e1 = EMPTY;
}
List12(E e0, E e1) {
this.e0 = Objects.requireNonNull(e0);
this.e1 = Objects.requireNonNull(e1);
}
}
list.of()
메서드를 통해서는 an unmodifiable list(ImmutableCollections)가 만들어진다.
Map.of()
메서드는 Entry(KeyValueHolder)를 이용하여 맵을 만들 수 있다.
public interface Map<K, V> {
static <K, V> Entry<K, V> entry(K k, V v) {
// KeyValueHolder checks for nulls
return new KeyValueHolder<>(k, v);
}
}
public class Quiz8_1 {
public static void main(String[] args) {
List<String> actors = List.of("Keanu", "Jessica");
actors.set(0, "Brad");
System.out.println(actors);
}
}
/* 출력 결과
* Exception in thread "main" java.lang.UnsupportedOperationException
* at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
* at java.base/java.util.ImmutableCollections$AbstractImmutableList.set(ImmutableCollections.java:260)
* */
removeIf()
: Collection
인터페이스의 default Method
이다.Collection
인터페이스의 메서드이기때문에, List
, Set
을 구현하거나 그 구현을 상속 받은 모든 클래스에서 이용할 수 있다.public interface Collection<E> extends Iterable<E> {
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
replaceAll()
: List
인터페이스의 default Method
이다.public interface List<E> extends Collection<E> {
default void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final ListIterator<E> li = this.listIterator();
while (li.hasNext()) {
li.set(operator.apply(li.next()));
}
}
}
public interface Map<K, V> {
// forEach
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch (IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
// comparingByKey
public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
}
// comparingByValue
public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
}
// getOrDefault
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
}
BiConsumer
키와 값을 인수로 받는다.코테에서 간간이 쓸만함
public interface Map<K, V> {
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return v;
}
default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
if ((oldValue = get(key)) != null) {
V newValue = remappingFunction.apply(key, oldValue);
if (newValue != null) {
put(key, newValue);
return newValue;
} else {
// 값을 만드는 함수가 Null을 반환하면 현재 매핑을 맵에서 삭제함
remove(key);
return null;
}
} else {
return null;
}
}
}
remove(key)
만이 아닌 remove(key,value)
를 통하여 contains(key) && equals(get(key),value)
를 대체할 수 있다.public interface Map<K, V> {
default boolean remove(Object key, Object value) {
Object curValue = get(key);
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
remove(key);
return true;
}
}
replaceAll()
: 앞서 다루었던 List
인터페이스의 replaceAll()
메서드와 비슷하다.replace()
: 키가 존재하면 값을 바꾼다.중복된 키가 없으면 putAll 메서드를 사용하면 된다.
하지만 중복된 키가 있으면 merge()
메서드를 사용한다.
public class Quiz8_2 {
public static void main(String[] args) {
Map<String, Integer> movies = new HashMap<>();
movies.put("JamesBond", 20);
movies.put("Matrix", 15);
movies.put("Harry Potter", 5);
Iterator<Map.Entry<String, Integer>> iterator = movies.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
if (entry.getValue() < 10) {
iterator.remove();
}
}
System.out.println(movies);
movies.clear();
movies.put("JamesBond", 20);
movies.put("Matrix", 15);
movies.put("Harry Potter", 5);
movies.entrySet().removeIf(entry -> entry.getValue() < 10);
System.out.println(movies);
// {Matrix=15, JamesBond=20}
}
}
잘 모르겠다..