Я искал достойную реализацию универсальной ленивой немодифицируемой реализации списка для обертывания моих записей результата поиска. Немодифицируемая часть задачи легка, поскольку она может быть достигнута Collections.unmodifiableList()
таким образом, я только должен разобраться в ленивой части.
Удивительно, наборы Google не имеет ничего для предложения; в то время как LazyList от Apache Наборы палаты общин не поддерживает дженериков.
Я нашел попытку создать что-то сверху наборов Google, но это, кажется, неполно (например, не поддерживает size()
), устаревший (не компилирует с 1,0 финалом) и требующий некоторых внешних классов, но мог использоваться в качестве хорошей начальной точки для создания моего собственного класса.
Кто-либо знает о какой-либо хорошей реализации LazyList? В противном случае то, какая опция, Вы думаете, лучше:
java.util.AbstractList
;Любые другие предложения приветствуются.
Править: объяснение, почему мне нужен ленивый список.
У меня есть результат поиска Lucene (TopDocs), который является в основном набором указателей на документы Lucene. Мой класс результата поиска взял бы эти указатели в качестве входа и возвратил бы список объектов, которые сделаны из извлеченных и иначе обработанных документов Lucene. Путем обертывания всего в ленивый список я хочу удостовериться, что я не делаю дорогой обработки, когда ненужный.
На самом деле я решил эту проблему другим способом. Вместо того, чтобы лениться и не изменять, я просто реализовал java.lang.Iterable
. Реализация вызывает исключение UnsupportedOperationException
в remove ()
.
Мне пришлось немного изменить некоторые другие части кода, от чего-то отказаться, но я считаю, что это был лучший выбор. Iterable
позволяет поместить его в цикл foreach.
Простите, что разочаровываю, если это не будет жизнеспособным выбором для кого-то в подобной ситуации, и большое спасибо за идеи.
Есть проект, который добавил функции Generics в общие коллекции Apache:
http://sourceforge.net/projects/collections/
( Коллекции Commons с Generics)
Решение Питера Мааса, на которое вы ссылаетесь, мне нравится - я настоятельно рекомендую вам поработать с ним, а не тратить время на его изобретение заново. Просто замените Factory
на Supplier
(входит в коллекцию Google).Его реализация subList также довольно умна, хотя имеет некоторые специфические последствия: если вы получите subList ()
и попытаетесь добавить элемент за пределы subList, вы не получите ] IndexOutOfBoundsException
(как и должен делать правильный подсписок), но вы вставите в список дополнительные элементы. Скорее всего, вам не понадобятся подсписки, поэтому самым безопасным было бы реализовать этот метод, выбрасывая UnsupportedOperationException
(или построив LazyList, который имеет дополнительный флаг, разрешено ли ему увеличиваться с помощью get ()
вызывает сверх своего размера: если он создан с помощью subList
, то это не так).
size ()
поддерживается (автоматически самим ForwardingList
).
Обновление: Обратите внимание, что, как сказал Кевин, вы не объяснили, почему что-то подобное действительно может быть тем, что вам нужно. Кроме того, возможно, вы захотите подумать, применимо ли что-то вроде этого:
final Supplier<T> supplier = ...;
Map<Integer, T> graphs = new MapMaker()
.makeComputingMap(
new Function<Integer, T>() {
public T apply(Integer index) {
return supplier.get();
}
});
Поскольку List
и Map
более или менее представляют один и тот же абстрактный тип данных, и, поскольку из вашего комментария следует, что (1) вы не хотите, чтобы значения NULL рассматривались как элементы (хорошо!), и (2) ваша структура может быть разреженной, тогда как фактический ArrayList будет расточительным.
Google-коллекции и метод Guava Lists.transform
дают вам лень, к которой вы стремитесь. Не хуже использовать Iterables.transform
.
Но, если вы также обеспокоены тем, что результаты должны быть кэшированы после первого создания, ну ... прямо сейчас это лучшее, что я придумал, и это не будет очень утешительно:
List<Supplier<ExpensiveResult>> suppliers =
ImmutableList.copyOf(Lists.transform(keys,
new Function<Key, Supplier<ExpensiveResult>>() {
public Supplier<ExpensiveResult> apply(Key key) {
return Suppliers.memoize(Suppliers.compose(
myExpensiveFunction(),
Suppliers.ofInstance(key)));
}
}));
return Lists.transform(suppliers, ThisClass.<ExpensiveResult>supplyFunction());
. . .
private static <T> Function<Supplier<T>, T> supplyFunction() {
return new Function<Supplier<T>, T>() {
public T apply(Supplier<T> supplier) {
return supplier.get();
}
};
}
Да, вы можете смеяться. И вам, вероятно, следует. Я ... не очень рекомендую это. По-прежнему может быть меньше кода, чем то, что вы сейчас делаете. И я только что проверил .. работает.