/** * Removes all of the elements of this collection that satisfy the given * predicate. Errors or runtime exceptions thrown during iteration or by * the predicate are relayed to the caller. * * @implSpec * The default implementation traverses all elements of the collection using * its {@link #iterator}. Each matching element is removed using * {@link Iterator#remove()}. If the collection's iterator does not * support removal then an {@code UnsupportedOperationException} will be * thrown on the first matching element. * * @param filter a predicate which returns {@code true} for elements to be * removed * @return {@code true} if any elements were removed * @throws NullPointerException if the specified filter is null * @throws UnsupportedOperationException if elements cannot be removed * from this collection. Implementations may throw this exception if a * matching element cannot be removed or if, in general, removal is not * supported. * @since 1.8 */ defaultbooleanremoveIf(Predicate<? super E> filter) { Objects.requireNonNull(filter); booleanremoved=false; final Iterator<E> each = iterator(); while (each.hasNext()) { if (filter.test(each.next())) { each.remove(); removed = true; } } return removed; }
디폴트 메소드로는 boolean equals(Object o), int hashCode(); 는 제공하면 안된다.
인터페이스와 추상골격 구현 클래스의 장점을 함께 제공하는 식으로 인터페이스와 추상 클래스의 장점을 모두 취하는 방법도 있다.(템플릿 메서드 패턴)
관례상 인터페이스 이름이 Interface면 그 골격 구현클래스의 이름은 AbstractInterface라고 명명한다.(이부분은 Abstract 클래스인데 음 모르겠다.) 템플릿 메소트 패턴을 설명하는듯
// 코드 20-1 골격 구현을 사용해 완성한 구체 클래스 (133쪽) publicclassIntArrays { static List<Integer> intArrayAsList(int[] a) { Objects.requireNonNull(a);
// 다이아몬드 연산자를 이렇게 사용하는 건 자바 9부터 가능하다. // 더 낮은 버전을 사용한다면 <Integer>로 수정하자. returnnewAbstractList<Integer>() { @Override public Integer get(int i) { return a[i]; // 오토박싱(아이템 6) }
@Override public Integer set(int i, Integer val) { intoldVal= a[i]; a[i] = val; // 오토언박싱 return oldVal; // 오토박싱 }
// 코드 20-2 골격 구현 클래스 (134-135쪽) publicabstractclassAbstractMapEntry<K, V> implementsMap.Entry<K, V> { // 변경 가능한 엔트리는 이 메서드를 반드시 재정의해야 한다. @Override public V setValue(V value) { thrownewUnsupportedOperationException(); }
// Map.Entry.equals의 일반 규약을 구현한다. @Override publicbooleanequals(Object o) { if (o == this) returntrue; if (!(o instanceof Map.Entry)) returnfalse; Map.Entry<?, ?> e = (Map.Entry) o; return Objects.equals(e.getKey(), getKey()) && Objects.equals(e.getValue(), getValue()); }
// Implementation Note: SimpleEntry and SimpleImmutableEntry // are distinct unrelated classes, even though they share // some code. Since you can't add or subtract final-ness // of a field in a subclass, they can't share representations, // and the amount of duplicated code is too small to warrant // exposing a common abstract class.
/** * An Entry maintaining a key and a value. The value may be * changed using the <tt>setValue</tt> method. This class * facilitates the process of building custom map * implementations. For example, it may be convenient to return * arrays of <tt>SimpleEntry</tt> instances in method * <tt>Map.entrySet().toArray</tt>. * * @since 1.6 */ publicstaticclassSimpleEntry<K,V> implementsEntry<K,V>, java.io.Serializable { privatestaticfinallongserialVersionUID= -8499721149061103585L;
privatefinal K key; private V value;
/** * Creates an entry representing a mapping from the specified * key to the specified value. * * @param key the key represented by this entry * @param value the value represented by this entry */ publicSimpleEntry(K key, V value) { this.key = key; this.value = value; }
/** * Creates an entry representing the same mapping as the * specified entry. * * @param entry the entry to copy */ publicSimpleEntry(Entry<? extends K, ? extends V> entry) { this.key = entry.getKey(); this.value = entry.getValue(); }
/** * Returns the key corresponding to this entry. * * @return the key corresponding to this entry */ public K getKey() { return key; }
/** * Returns the value corresponding to this entry. * * @return the value corresponding to this entry */ public V getValue() { return value; }
/** * Replaces the value corresponding to this entry with the specified * value. * * @param value new value to be stored in this entry * @return the old value corresponding to the entry */ public V setValue(V value) { VoldValue=this.value; this.value = value; return oldValue; }
/** * Compares the specified object with this entry for equality. * Returns {@code true} if the given object is also a map entry and * the two entries represent the same mapping. More formally, two * entries {@code e1} and {@code e2} represent the same mapping * if<pre> * (e1.getKey()==null ? * e2.getKey()==null : * e1.getKey().equals(e2.getKey())) * && * (e1.getValue()==null ? * e2.getValue()==null : * e1.getValue().equals(e2.getValue()))</pre> * This ensures that the {@code equals} method works properly across * different implementations of the {@code Map.Entry} interface. * * @param o object to be compared for equality with this map entry * @return {@code true} if the specified object is equal to this map * entry * @see #hashCode */ publicbooleanequals(Object o) { if (!(o instanceof Map.Entry)) returnfalse; Map.Entry<?,?> e = (Map.Entry<?,?>)o; return eq(key, e.getKey()) && eq(value, e.getValue()); }
/** * Returns the hash code value for this map entry. The hash code * of a map entry {@code e} is defined to be: <pre> * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^ * (e.getValue()==null ? 0 : e.getValue().hashCode())</pre> * This ensures that {@code e1.equals(e2)} implies that * {@code e1.hashCode()==e2.hashCode()} for any two Entries * {@code e1} and {@code e2}, as required by the general * contract of {@link Object#hashCode}. * * @return the hash code value for this map entry * @see #equals */ publicinthashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); }
/** * Returns a String representation of this map entry. This * implementation returns the string representation of this * entry's key followed by the equals character ("<tt>=</tt>") * followed by the string representation of this entry's value. * * @return a String representation of this map entry */ public String toString() { return key + "=" + value; }
}
단순구현은 골격 구현의 작은 변종으로 위의 AbstractMap.SimpleEntry가 좋은 예이다. 단순 구현은 쉽게 말해 동작하는 가장 단순한 구현이다. 단순구현은 그래로 써도 되고 필요에 맞게 확장해도 된다.