Google Коллекции Поставщики и Найти - PullRequest
1 голос
/ 19 февраля 2010

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

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

Ответы [ 3 ]

5 голосов
/ 19 февраля 2010

Учитывая ваш комментарий к ответу Calm Storm (желание не звонить 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());

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

3 голосов
/ 19 февраля 2010

Вы спрашивали, как это сделать, используя 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; если ваш код вызывает это нормальное вхождение, которое, как ожидается, нужно будет проверить, вы можете вернуть ноль.

0 голосов
/ 19 февраля 2010

Что с этим не так?

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;
     }
});

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

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

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

ОБНОВЛЕНИЕ: в этом случае поиск является неправильным методом. На самом деле вам нужна такая функция, которая может возвращать два значения. Если вы используете commons-collection, тогда вы можете использовать DefaultMapEntry или просто вернуть Object [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 или хеш-картой размера 1 или массивом длины 2:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...