2017-02-03 4 views
5

У меня есть код ниже.Как перебирать вложенные петли, ссылаясь на родительские элементы, используя Java 8 Streams и Lambdas?

public static ModuleKey getDeployableModuleFromModulesList(List<Module> modules) { 
     ModuleKey deployableModuleKey = null; 
     for(Module module : modules) { 
      List<Artifact> artifacts = module.getArtifacts(); 
      for(Artifact artifact : artifacts) { 
       if(artifact.getType().equals("ear")) { 
        return module.getKey(); 
       } else if(!artifact.getType().equals("ear")) { 
        if(artifact.getType().equals("war")) { 
         deployableModuleKey = module.getKey(); 
        } 
       } 
      } 
     } 
     return deployableModuleKey; 
    } 

Этот код находит первый «deployableModuleKey» с ключом = «ухо» или последнего с ключом = «войны». Я хочу достичь той же функциональности, что и выше, используя Java 8 Streams и Lambdas.

До сих пор, что я попытался это:

modules.stream().flatMap(e -> e.getArtifacts().stream()) 
    .filter(e -> e.getType().equals("ear")).findFirst() 
    .orElseGet(() -> modules.stream().flatMap(e -> e.getArtifacts().stream()) 
    .filter(e -> e.getType().equals("war")).reduce((a, b) -> b).orElse(null)); 

выше фрагмент кода будет возвращать объект типа Artifact вместо Module. Я хочу получить тот модуль, где артефакт соответствует условиям. Как только я нахожу модуль, я могу вернуть ключ, выполнив module.getKey(). Для этого я хотел бы знать, как мы ссылаемся на элементы родительского цикла.

Я не уверен, что мой код Java 8 полностью верен.
Может ли кто-нибудь помочь мне в этом отношении?

+1

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

+0

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

ответ

0

Я выяснил решение моей проблемы.

public static ModuleKey getDeployableModuleFromModulesList(List<Module> modules) { 
    Optional<ModuleKey> op = modules.stream().filter(module -> module.getArtifacts().stream().anyMatch(artifact -> artifact.getType().equals("ear"))).map(module -> module.getKey()).findFirst(); 
    if (!op.isPresent()) { 
     op = modules.stream().filter(module -> module.getArtifacts().stream().anyMatch(artifact -> artifact.getType().equals("war"))).map(module -> module.getKey()).reduce((a, b) -> b); 
    } 
    return op.orElse(null); 
} 

В любом случае, другие решения также приветствуются. Если кто-то добавит другое решение, я попробую все.

0

Вещь с потоками, если вы изменили свой поток, используя промежуточную операцию, например filter или map, вы не можете вернуться к значениям из предыдущей операции. Поэтому вам нужно найти обходные пути, чтобы всегда держать (в вашем случае Module) значение, которое вы хотите использовать в своем потоке. В следующем решении я открываю два вторичных потока с операциями anyMatch, которые дают положительное значение, если модуль содержит артефакт, содержащий требуемый ключ.

Это должно сделать трюк:

ModuleKey key = Optional.ofNullable(modules.stream().filter(m -> m.getArtifacts().stream() 
    .anyMatch(a -> a.equals("ear"))).findFirst().orElse(modules.stream() 
    .filter(m -> m.getArtifacts().stream().anyMatch(a -> a.equals("war"))) 
    .reduce((a, b) -> b).orElse(null))).map(Module::getKey).orElse(null); 

Чтобы найти первый элемент, используйте findFirst, который возвращает Optional<T>. Мы связываем это Optional с Optional#orElse, который разворачивает его и, если он пуст, возвращает другое значение (в данном случае используя reduce((a, b) -> b), чтобы найти последний элемент). Если ничего не найдено, мы не хотим, чтобы код выдавал код NullPointerException. Поэтому, прежде чем мы назовем метод getKey, мы обернем все это в Optional с Optional.ofNullable и установите для orElse значение null - значение по умолчанию, указанное в вашем коде.

В качестве примечания,

else if(!artifact.getType().equals("ear")) { 
    if(artifact.getType().equals("war")) { 
    } 
} 

может быть сведен к

else if(artifact.getType.equals("war")) { 
} 
+0

Я получаю следующие ошибки компиляции, если я использую ваш фрагмент кода , 'Фильтр метода (( m) -> {}) не определен для типа List ' и 'Метод getKey() не определен для типа ModuleUtil'. Метод getKey() 'является частью объекта' Module'. –

+0

@RITZXAVI Я прототипировал свой код в блокноте ++ вместо обычной IDE, и появились новые глюки. Я отредактировал свой ответ, чтобы исправить их, скажите, если вы все еще испытываете проблемы. – MikaelF

+0

Теперь я получаю эту ошибку. 'Метод orElse (Module) в типе Необязательный не применим для аргументов (необязательно )' –

0

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

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

public static ModuleKey getDeployableModuleFromModulesList(List<Module> modules) { 

    return findEARKey(modules.stream()) 
      .orElse(findWARKey(modules.stream()).orElse(null)); 

} 

public static Optional<ModuleKey> findEARKey(Stream<Module> moduleStream){ 

    return moduleStream.flatMap(e -> e.getArtifacts().stream()) 
      .filter(e -> e.getType().equals("ear")) 
      .map(Artifact::getKey).findFirst(); 
} 

public static Optional<ModuleKey> findWARKey(Stream<Module> moduleStream){ 

    return moduleStream.flatMap(e -> e.getArtifacts().stream()) 
      .filter(e -> e.getType().equals("war")) 
      .map(Artifact::getKey).findFirst(); 
} 
+0

Я думаю, что ваш код хорош, если я хочу «deployableModuleKey» с типом = «ухом» ** ИЛИ ** «war». Но вместо этого я хочу, чтобы это был первый «deployableModuleKey» с типом = «ухом». Если 'ear' нет, то я хочу вернуть последний модульKey с типом = 'war'. –

+1

Кроме того, этот код возвращает ключ артефакта, а не ключ модуля –

+0

Да, в объекте 'Artifact' нет атрибута' key'. –