Вопрос

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

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

Это было полезно?

Решение

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

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

Другие советы

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

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
}

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

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

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

Где поставленное производство - еще один класс.

ОБНОВЛЕНИЕ: В этом случае найти неправильный метод. Вам действительно нужна такая пользовательская функция, которая может вернуть два значения. Если вы используете Commons-Collense, вы можете использовать по умолчанию Mapentry или просто вернуть объект [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);
        }
    }
}

Замените по умолчанию мапентрика списком размера 2 или хэш -карты размера 1 или массивом длины 2 :)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top