Со стандартным API вам придется делать это самостоятельно, то есть расширять один из классов отсортированных множеств и добавлять желаемую логику к методам add()
и addAll()
. Не должно быть слишком сложно.
Кстати, я не совсем понимаю ваш пример:
t1.add(9);
// [1,2,3]
Разве набор не должен содержать [1,2,9]
впоследствии?
Редактировать : Думаю, теперь я понимаю: вы хотите сохранить только самые маленькие 3 элемента, которые были добавлены в набор, верно?
Редактировать 2 : Пример реализации (не оптимизирован) может выглядеть следующим образом:
class LimitedSortedSet<E> extends TreeSet<E> {
private int maxSize;
LimitedSortedSet( int maxSize ) {
this.maxSize = maxSize;
}
@Override
public boolean addAll( Collection<? extends E> c ) {
boolean added = super.addAll( c );
if( size() > maxSize ) {
E firstToRemove = (E)toArray( )[maxSize];
removeAll( tailSet( firstToRemove ) );
}
return added;
}
@Override
public boolean add( E o ) {
boolean added = super.add( o );
if( size() > maxSize ) {
E firstToRemove = (E)toArray( )[maxSize];
removeAll( tailSet( firstToRemove ) );
}
return added;
}
}
Обратите внимание, что tailSet()
возвращает подмножество, включая параметр (если оно есть в наборе). Это означает, что если вы не можете рассчитать следующее более высокое значение (не обязательно должно быть в наборе), вам придется прочитать этот элемент. Это сделано в коде выше.
Если вы можете рассчитать следующее значение, например, если у вас есть набор целых чисел, достаточно сделать что-то tailSet( lastElement + 1 )
, и вам не придется читать последний элемент.
Кроме того, вы можете перебрать набор самостоятельно и удалить все элементы, которые следуют за последним, который вы хотите сохранить.
Другой альтернативой, хотя это может быть больше работы, будет проверка размера перед вставкой элемента и удаление соответственно.
Обновление : как правильно указал msandiford, первый элемент, который должен быть удален, - это элемент с индексом maxSize
. Таким образом, нет необходимости читать (повторно добавлять?) Последний требуемый элемент.
Важное примечание:
Как правильно указал @DieterDP, приведенная выше реализация нарушает контракт API Collection#add()
, который гласит, что если коллекция отказывается добавлять элемент по любой причине, кроме того, что она является дубликатом, исключение должно быть брошено .
В приведенном выше примере элемент сначала добавляется, но может быть снова удален из-за ограничений размера или других элементов, что может нарушить договор.
Чтобы исправить это, вы можете изменить add()
и addAll()
, чтобы они выдавали исключения в этих случаях (или, может быть, в любом случае, чтобы сделать их непригодными для использования) и предоставлять альтернативные методы для добавления элементов, которые не нарушают какие-либо существующий контракт API.
В любом случае приведенный выше пример следует использовать с осторожностью , поскольку его использование с кодом, который не знает о нарушениях, может привести к нежелательным и трудным для отладки ошибкам.