2010-02-19 2 views
1

Я ищу метод Google Collections, который возвращает первый результат последовательности поставщиков, который не возвращает null.Google Collections Suppliers and Find

Я искал использование Iterables.find(), но в своем Predicate мне пришлось бы позвонить моему поставщику, чтобы сравнить результат с нулем, а затем снова позвонить ему, как только метод find вернет поставщика.

ответ

5

Учитывая ваш комментарий Успокоить ответ Шторма (желание не называть Supplier.get() дважды) , то как:

private static final Function<Supplier<X>, X> SUPPLY = new Function<....>() { 
    public X apply(Supplier<X> in) { 
     // If you will never have a null Supplier, you can skip the test; 
     // otherwise, null Supplier will be treated same as one that returns null 
     // from get(), i.e. skipped 
     return (in == null) ? null : in.get(); 
    } 
} 

затем

Iterable<Supplier<X>> suppliers = ... wherever this comes from ... 

Iterable<X> supplied = Iterables.transform(suppliers, SUPPLY); 

X first = Iterables.find(supplied, Predicates.notNull()); 

отмечают, что Ite который исходит из Iterables.transform(), оценивается лениво, поэтому, как Iterables.find() петли над ним, вы оцениваете только первый, не null, - возвратный, и только один раз.

+1

+1 для ответа на вопрос, который задал хорошо. Тем не менее, я думаю, что заданный вопрос должен был быть «что это лучший способ сделать это», а не «что такое способ, который использует коллекции Google», поэтому я предложил еще один ответ. –

+0

Это работало для меня. – pledge

+0

Тогда вы должны принять это как ответ. – harschware

-2

Что в этом плохого?

List<Supplier> supplierList = //somehow get the list 
Supplier s = Iterables.find(supplierList, new Predicate<Supplier>(){ 
    boolean apply(Supplier supplier) { 
     return supplier.isSomeMethodCall() == null; 
    } 
    boolean equals(Object o) { 
     return false; 
    } 
}); 

Вы пытаетесь сохранить некоторые строки? Единственная оптимизация, о которой я могу думать, - это статический импорт находки, чтобы вы могли избавиться от «Итераторов». Кроме того, предикат является анонимным внутренним классом, если вам это нужно в более чем одном месте вы можете создать класс, и это будет выглядеть так,

List<Supplier> supplierList = //somehow get the list 
Supplier s = find(supplierList, new SupplierPredicateFinder()); 

Где SupplierPredicateFinder другой класс.

ОБНОВЛЕНИЕ: В этом случае поиск является неправильным методом. Вам действительно нужна такая настраиваемая функция, которая может вернуть два значения. Если вы используете коллекцию commons, вы можете использовать DefaultMapEntry или просто можете вернуть объект [2] или Map.Entry.

public static DefaultMapEntry getSupplier(List<Supplier> list) { 
    for(Supplier s : list) { 
     Object heavyObject = s.invokeCostlyMethod(); 
     if(heavyObject != null) { 
      return new DefaultMapEntry(s, heavyObject); 
     } 
    } 
} 

Заменить DefaultMapEntry со списком размером 2 или HashMap размера 1 или массив длиной 2 :)

+0

В интерфейсе Поставщика (Google Collections) есть один метод, называемый get(). В этом много времени вычисляется. Iterables.find возвращает Поставщика, когда предикат совпадает, а не результат get(). Поэтому после результата find() мне нужно будет снова вызвать get, который должен будет снова выполнить вычисление. Я мог бы использовать MemoisingSupplier, но было бы лучше, если бы метод find вернул результат Поставщика, а не самого Поставщика. – pledge

+0

Обновлен ответ с некоторыми примерами кода! –

+0

Этот ответ некогерентен. Первая половина недопустима в соответствии с текстом исходного вопроса. Во второй половине, почему вы возвращаете как поставщика, так и heavyObject, когда пользователю нужен только объект heavyObject? Я обеспокоен тем, что мы будем так быстро рекомендовать Map.Entry/Object [2] взломать (и это гротескный хак) для всех, кроме тех случаев, когда * действительно * требуется. –

3

Вы спрашивали, как это сделать с помощью Google Collections, но вот как вы это сделаете, не используя Google Collections. Сравните это с ответом Коуэна (что является хорошим ответом) - что легче понять?

private static Thing findThing(List<Supplier<Thing>> thingSuppliers) { 
    for (Supplier<Thing> supplier : thingSuppliers) { 
    Thing thing = supplier.get(); 
    if (thing != null) { 
     return thing; 
    } 
    } 
    // throw exception or return null 
} 

Вместо комментария - если это произошло по вине вызывающему вашего класса, бросить IllegalArgumentException или IllegalStateException в зависимости от обстоятельств; если этого не должно было быть, используйте AssertionError; если это нормально, ваш код, который вызывает это ожидание, должен проверяться, вы можете вернуть null.

+0

Это решение, которое я изначально имел, я должен был действительно разместить его в вопросе. Однако, поскольку мы находили некоторые полезные функции для Predicates и Functions, я искал, было ли что-то вроде Suppliers.firstSupplied. Как показывает предложение Cowan (рабочий), это, вероятно, случай, когда функциональный стиль в Java делает менее понятный код. Тесты проходят с обоими решениями. – pledge

Смежные вопросы