Хорошо использует для Apache CollectionUtils - PullRequest
2 голосов
/ 25 января 2009

Я нашел класс CollectionUtils год или около того назад, и некоторые методы, такие как, собирать и преобразовывать, кажутся действительно классными, однако мне еще предстоит найти применение, где это не было бы синтаксически чище и \ или проще просто написать логику с помощью простого цикла.

Нашел ли кто-нибудь уникальное \ полезное применение для этих методов (преобразование, предикатная коллекция, сбор и т. Д.), Например методы, которые принимают преобразователь или предикат в качестве аргумента?

Ответы [ 5 ]

2 голосов
/ 04 февраля 2009

collect () полезно, когда у вас есть возможные альтернативные представления ваших объектов.

Например, недавно я имел дело с фрагментом кода, который должен был соответствовать спискам объектов из двух разных источников. Эти объекты были разных классов, так как они использовались в разных точках кода, но для моих целей имели одни и те же соответствующие понятия (т.е. у них обоих был идентификатор, у обоих был путь свойства, у обоих был флаг «каскад» и т. Д.) .

Я обнаружил, что гораздо проще определить простое промежуточное представление этих свойств (как внутренний класс), определить преобразователи для обоих классов конкретных объектов (опять же, очень просто, поскольку для вывода свойств используются только соответствующие методы доступа) и затем используйте collect(), чтобы преобразовать мои входящие объекты в промежуточное представление. Как только они появятся, я смогу использовать стандартные методы коллекций для сравнения и манипулирования двумя наборами.

Итак, в качестве (полу) конкретного примера, скажем, мне нужен метод для проверки того, что набор объектов на уровне представления является подмножеством объектов, кэшированных на уровне данных. С подходом, изложенным выше, это будет сделано примерно так:

public boolean isColumnSubset(PresSpec pres, CachedDataSpec dataSpec)
{
   final List<IntermediateRepresentation> presObjects = CollectionUtils.collect(pres.getObjects(), PRES&#95;TRANSFORMER);
   final List<IntermediateRepresentation> dataObjects = CollectionUtils.collect(dataSpec.getCached(), DATA&#95;TRANSFORMER);

   return dataObjects.containsAll(presObjects);
}

Для меня это гораздо более читабельно, поскольку последняя строка передает реальный смысл того, что метод делает , чем эквивалент с циклами:

public boolean isColumnSubset(PresSpec pres, CachedDataSpec dataSpec)
{
   for (PresSpecificObject presObj : pres.getObjects())
   {
      boolean matched = false;
      for (CachedDataObject dataObj : dataSpec.getCached())
      {
         if (areObjectsEquivalent(presObj, dataObj)) // or do the tests inline but a method is cleaner
         {
            matched = true;
            break;
         }
      }

      if (matched == false)
      {
         return false;
      }
   }

   // Every column must have matched
   return true;
}

Эти два, вероятно, примерно так же эффективны, но с точки зрения читабельности я бы сказал, что первый намного легче понять сразу. Несмотря на то, что в целом получается больше строк кода (из-за определения внутреннего класса и двух преобразователей), отделение реализации обхода от действительной логики «истина или ложь» делает последнюю намного понятнее. Плюс, если у вас есть какие-либо метрики KLOC, они тоже не могут быть бусинками. ; -)

2 голосов
/ 25 января 2009

Я думаю, что ключевым вопросом является разработка / кодирование для гибкости.

Если у вас есть один вариант использования (например, выбор членов коллекции, которые удовлетворяют некоторому определенному условию), то кодирование относительно простого цикла вручную работает. С другой стороны ...

Предположим, что набор возможных условий стал большим или даже может быть составлен на лету во время выполнения (даже динамически, на основе пользовательского ввода / взаимодействия). Или предположим, что было несколько очень сложных условий, которые можно объединить с операторами (например, A и B, C, а не D и т. Д.) В еще большее число случаев.

Предположим, что после выбора была произведена какая-то другая обработка результирующей коллекции.

Теперь рассмотрим структуру кода, которая может возникнуть в результате грубого, поточного подхода к написанию вышесказанного: внешний цикл, содержащий сложный процесс принятия решения для определения, какой тест (ы) выполнить, смешанный вместе с кодом что делает одну или несколько вещей с «выжившими» членами коллекции. Такой код имеет тенденцию быть (и особенно со временем сопровождаемым) трудным для понимания и трудным для изменения без риска появления дефектов.

Таким образом, цель состоит в том, чтобы следовать стратегии, в которой каждый аспект:

  • базовый процесс "выбрать что-то",
  • предикаты, которые выражают элементарные критерии,
  • объединение операторов, которые составляют предикаты, и
  • трансформаторы, которые работают на значениях,

можно кодировать и тестировать независимо, а затем привязывать вместе при необходимости.

1 голос
/ 25 января 2009

Хотя я согласен с Ури в принципе, без замыканий или литералов функций или чего-то еще, Java требует довольно высоких синтаксических затрат, чтобы фактически использовать такие методы, как сбор, преобразование и т. Д. Во многих случаях фактические строки кода - это такой же или больше, чем если бы вы написали простой цикл. addAll, removeAll и все их друзья, которые не принимают функциональные объекты в качестве аргументов, тем не менее необходимы.

Все это также относится к одинаково хорошему API коллекций Google .

Печально, что у Sun есть возможность исправить эти проблемы в Java 7, но, похоже, они не будут . Трусы.

0 голосов
/ 25 января 2009

Хотя мы не используем CollctionUtils, мы внедрили несколько подобных утилит сами по себе и из тех, которые мы часто используем

пусто (Коллекция c)

для проверки коллекций, строк и т. П. На пустоту

есть (...)

, который только возвращает! Empty (...)

mapToProperty (коллекция c, свойство String, класс newType)

это сопоставляет коллекцию T1 с коллекцией T2, используя отражение, чтобы вызвать "свойство"

взорваться (Коллекция c, String sep)

Отдельная строка с элементами c

0 голосов
/ 25 января 2009

Я не уверен, что согласен с вашим утверждением ...

Простой цикл добавляет сложности и менее "читабелен и очевиден", чем вызов с разумным именем.

Рефакторинг евангелистов будет утверждать, что ваша цель, как правило, должна заключаться в создании плоских и коротких функций, которые вызывают другие операции. Хотя addAll, find и другие методы легко реализовать самостоятельно, для избежания их потребуется, чтобы читатель понял что-то более сложное, чем одно слово, и это может привести к репликации кода.

ИМХО, CollectionUtils на самом деле представляет более чистые операции, чем стандартная библиотека Java-коллекций.

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