2017-02-15 14 views
2

У меня есть для-заявления в Java-7, и это отлично работает:использовать, если-другое заявление в лямбда-выражения Java-8

Character cha = new Character(','); 
String ncourseIds = null; 
String pastCourseIds = null; 
for (EquivalentCourse equivalentCourse : equivalentCourses) { 
    if(equivalentCourse.getNcourse() != null){ 
    ncourseIds += equivalentCourse.getNcourse().getId()+ ","; 
    } else if(equivalentCourse.getPastCourse() != null) { 
    pastCourseIds +=equivalentCourse.getPastCourse().getId()+","; 
    } 
} 
if(!ncourseIds.isEmpty() &&cha.equals(ncourseIds.charAt(ncourseIds.length()-1))) { 
    ncourseIds = ncourseIds.substring(0, ncourseIds.length()-1); 
} 
if(!pastCourseIds.isEmpty()&& cha.equals(pastCourseIds.charAt(pastCourseIds.length()-1))) { 
    pastCourseIds = pastCourseIds.substring(0,pastCourseIds.length()-1); 
} 

Теперь я хочу, чтобы преобразовать код для Stream & collect в Java- 8, я реализую половину моего дела о фильтре не нулевой Ncourse:

equivalentCourses.stream().filter(obj -> obj.getNcourse() != null) 
       .map(obj -> obj.getNcourse().getId()).collect(Collectors.joining(",")); 

, но я не знаю, чтобы осуществить это else-statement. любая помощь?

+4

Почему вы используете 'Character' вместо' char'? Это делает ваш код труднее читать * и * тратит ресурсы. Хотя вам это совсем не нужно, если вы замените '! NcourseIds.isEmpty() && ha.equals (ncourseIds.charAt (ncourseIds.length() - 1))' с помощью простого 'ncourseIds.endsWith (", ")' и аналогично: '! pastCourseIds.isEmpty() && cha.equals (pastCourseIds.charAt (pastCourseIds.length() - 1))' с 'pastCourseIds.endsWith (", ")'. Чтобы собрать две строки с потоками, вы можете просто выполнить две потоковые операции. – Holger

+3

@ Хольгер уже сказал это: используйте две операции потока (один для 'getNcourse()! = Null' и один для' getNcourse() == null && getPastCourse()! = Null'). –

ответ

3

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

String ncourseIds = equivalentCourses.stream() 
    .filter(equivalentCourse -> equivalentCourse.getNcourse() != null) 
    .map(EquivalentCourse::getNcourse) 
    .map(x -> String.valueOf(x.getId())) 
    .collect(Collectors.joining(", ")); 

String pastCourseIds = equivalentCourses.stream() 
    .filter(equivalentCourse -> equivalentCourse.getNcourse() == null 
      && equivalentCourse.getPastCourse() != null) 
    .map(EquivalentCourse::getPastCourse) 
    .map(x -> String.valueOf(x.getId())) 
    .collect(Collectors.joining(", ")); 

Это также код, ориентированный на получающиеся две строки, с эффективным соединением.

Кстати, если это для строки SQL, вы можете использовать PreparedStatement с Array.


Украшение, как прокомментировал @Holger:

String ncourseIds = equivalentCourses.stream() 
    .map(EquivalentCourse::getNcourse) 
    .filter(Objects::nonNull) 
    .map(NCourse::getId) 
    .map(String::valueOf) 
    .collect(Collectors.joining(", ")); 

String pastCourseIds = equivalentCourses.stream() 
    .filter(equivalentCourse -> equivalentCourse.getNcourse() == null) 
    .map(EquivalentCourse::getPastCourse) 
    .filter(Objects::nonNull) 
    .map(EquivalentCourse::getPastCourse) 
    .map(PastCourse::getId) 
    .map(String::valueOf) 
    .collect(Collectors.joining(", ")); 
+0

Хорошее использование двоеточия! – Cuga

+2

Вы можете упростить, изменив порядок. Первый поток op: '.map (EquivalentCourse :: getNcourse) .filter (Objects :: nonNull)', второй поток op: '.filter (equalCourse -> equalCourse.getNcourse() == null) .map (EquivalentCourse :: getPastCourse) .filter (Объекты :: nonNull) '. – Holger

+1

@ Хольджер, вы правы, а также getId можно улучшить с помощью некоторых знаний о классе. –

0

Update

Чтобы добавить альтернативу, вот что код будет выглядеть, чтобы сделать работу с двумя filter() операций. Обратите внимание, что это влияет на повторение итерации всей коллекции во второй раз, что может повлиять на производительность, если это большая коллекция.

Я также пошел вперед и упростил некоторые из логики в отношении соединения строк. Поправьте меня, если я там что-то пропустил.

final List<String> courseIdList = new ArrayList<>(); 
final List<String> pastCourseIdList = new ArrayList<>(); 

equivalentCourses.stream().filter((current) -> current.getNcourse() != null) 
       .forEach((current) -> courseIdList.add(current.getNcourse().getId())); 

equivalentCourses.stream().filter((current) -> current.getNcourse() != null && current.getPastCourse() != null) 
       .forEach((current) -> pastCourseIdList.add(current.getPastCourse().getId())); 

String ncourseIds = String.join(",", courseIdList); 
String pastCourseIds = String.join(",", pastCourseIdList); 

Оригинальный ответ

Для вашего случая использования, это может сделать больше смысла использовать forEach() лямбда. Это будет самый простой способ сделать перевод.

java.lang.Character cha = new java.lang.Character(','); 

final StringBuilder ncourseIdBuilder = new StringBuilder(); 
final StringBuilder pastCourseIdBuilder = new StringBuilder(); 
equivalentCourses.stream().forEach((equivalentCourse) -> { 
    if (equivalentCourse.getNcourse() != null) { 
     ncourseIdBuilder.append(equivalentCourse.getNcourse().getId()).append(","); 
    } else if (equivalentCourse.getPastCourse() != null) { 
     pastCourseIdBuilder.append(equivalentCourse.getPastCourse().getId()).append(","); 
    } 
}); 

String ncourseIds = ncourseIdBuilder.toString(); 
String pastCourseIds = pastCourseIdBuilder.toString(); 

if (!ncourseIds.isEmpty() && cha.equals(ncourseIds.charAt(ncourseIds.length() - 1))) { 
    ncourseIds = ncourseIds.substring(0, ncourseIds.length() - 1); 
} 
if (!pastCourseIds.isEmpty() && cha.equals(pastCourseIds.charAt(pastCourseIds.length() - 1))) { 
    pastCourseIds = pastCourseIds.substring(0, pastCourseIds.length() - 1); 
} 

Вы можете переписать код, используя filter() выражения, но это будет требовать большую переделку логики в условных, которая вводит риск вы можете сломать что-то, если это не тестируется. Логические изменения - это именно то, что @Holger и @Ole V.V. в своих комментариях к исходному вопросу.

Независимо от того, используете ли вы forEach() или фильтры, lambdas не может получить доступ к не конечным переменным внутри выражения, поэтому я добавил переменную final StringBuilder за пределы области действия цикла.

1

Вы можете группировать по условию, а затем переназначить:

public void booleanGrouping() throws Exception { 
    List<String> strings = new ArrayList<>(); 
    strings.add("ala"); 
    strings.add("ela"); 
    strings.add("jan"); 

    strings.stream() 
      .collect(
        Collectors.groupingBy(s -> s.endsWith("a")) // using function Obj -> Bool not predicate 
      ).entrySet() 
      .stream() 
      .collect(
        Collectors.toMap(
          e -> e.getKey() ? "Present" : "Past", 
          e -> e.getValue().stream().collect(Collectors.joining("")) 
        ) 
      ); 
} 

Первый поток группы по условию, вы должны использовать equivalentCourse.getNcourse() != null второй коллекции ReMap от значения до строки.Вы можете ввести:

enum PresentPast{ 
    Present, Past 
    PresentPast is(boolean v){ 
     return v ? Present : Past 
    } 
} 

и изменить e -> e.getKey() ? "Present" : "Past" на ENUM решение, основанное.

Edit:

Раствор для else if:

public Map<Classifier, String> booleanGrouping() throws Exception { 
    List<String> strings = new ArrayList<>(); 
    strings.add("ala"); 
    strings.add("ela"); 
    strings.add("jan"); 
    // our ifs: 
    /* 
     if(!string.endsWith("n")){ 
     }else if(string.startsWith("e")){} 

     final map should contains two elements 
     endsWithN -> ["jan"] 
     startsWithE -> ["ela"] 
     NOT_MATCH -> ["ala"] 

    */ 
    return strings.stream() 
      .collect(
        Collectors.groupingBy(Classifier::apply) // using function Obj -> Bool not predicate 
      ).entrySet() 
      .stream() 
      .collect(
        Collectors.toMap(
          e -> e.getKey(), 
          e -> e.getValue().stream().collect(Collectors.joining("")) 
        ) 
      ); 
} 

enum Classifier implements Predicate<String> { 
    ENDS_WITH_N { 
     @Override 
     public boolean test(String s) { 
      return s.endsWith("n"); 
     } 
    }, 
    STARTS_WITH_E { 
     @Override 
     public boolean test(String s) { 
      return s.startsWith("e"); 
     } 
    }, NOT_MATCH { 
     @Override 
     public boolean test(String s) { 
      return false; 
     } 
    }; 

    public static Classifier apply(String s) { 
     return Arrays.stream(Classifier.values()) 
       .filter(c -> c.test(s)) 
       .findFirst().orElse(NOT_MATCH); 
    } 
} 
+0

Это хорошее решение только для оператора 'if-else', но вопрос о инструкции' else-if'. В этом случае вам необходимо выполнить две операции потока. – MBec

+0

Я вижу :) Я исправлю это (вам нужно ввести немного другое условие), когда я вернусь на свой основной компьютер: D –

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

  • Нет связанных вопросов^_^