Извинения, что, наверное, худшее название, которое я использовал, но я не могу понять, как это выразить.

Я вызываю метод table.getColData (COL_1), который возвращает универсальный

public <T extends Object> List<T> getColData(final String col)

Я звоню дважды и получаю два списка строк. Я хочу объединить их и в конечном итоге это -

List<String> a = table.getColData(col1);
List<String> b = table.getColData(col2);

List <String> c = Stream.concat(a.stream(), b.stream()).collect(Collectors.toList());

Который работает хорошо, я думаю. Я не могу найти способ избежать двух объявлений, хотя и не получаю сообщение об ошибке, поскольку concat считает, что у него есть список объектов, которые не являются String s (подсказка: измените тип {{X2} } до List<Object>)?

Есть ли простой способ сделать это, чтобы он выглядел немного более отполированным ?!

5
gringogordo 21 Авг 2018 в 16:14

5 ответов

Лучший ответ

Вы ограничены выводом компилятора.

List <String> c = Stream.concat(getColDataStream(col1).stream(), getColDataStream(col2).stream()).collect(Collectors.toList());

Не может скомпилировать, потому что getColDataStream() возвращение выводится как List<Object>, так как вы не указываете целевой тип со стороны вызова.
Вы можете объединить два потока List<Object>, но это не даст Stream<String>, но Stream<Object>.
Ввод двух промежуточных переменных не является необходимым лучшим способом.

1) В качестве альтернативы, предложенной Хольгером, вы можете указать тип T со стороны цели:

 Stream.concat(table.<String>getColData(col1).stream(), table.<String>getColData(col2).stream()) 
       .collect(Collectors.toList());

2) Вы также можете преобразовать Stream<Object> в Stream<String> в операции map():

List<String> c = Stream.concat(table.getColData(col1).stream(), table.getColData(col2).stream())
                           .map(s -> (String) s)
                           .collect(Collectors.toList());

3) или введение дополнительного метода, который предотвращает любое явное приведение путем объединения потоков списков и сбора его в List, который он возвращает:

public <T> List<T> concatAndCollectToList(final List<T> a, List<T> b) {
    return Stream.concat(a.stream(), b.stream())
                 .collect(Collectors.toList());
}

Теперь вы можете сделать только:

List<String> c = concatAndCollectToList(table.getColData(col1), table.getColData(col2));
4
davidxxx 21 Авг 2018 в 14:20

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

public static <T> List<T> getColData(String col, Class<T> clazz) {
     // whatever you did as before
}

И в таком случае ваша безопасность типов будет на месте:

List<String> set = Stream.concat(
                     getColData("", String.class).stream(),
                     getColData("", String.class).stream())
                   .collect(Collectors.toList());
4
Eugene 21 Авг 2018 в 13:57

Во-первых, T extends Object является избыточным, поскольку каждый объект T простирается от Object с момента определения.

Поскольку метод возвращает List<T>, во время компиляции неизвестно, какой тип T, поэтому невозможно передать эти два общих результата в Stream - собранный результат равен {{X3} } независимо от T.

Вы должны сопоставить каждое из значений с String - на этом этапе вы должны убедиться, что все элементы списка можно преобразовать в String, используя приведение или преобразование:

List<String> c = Stream
                 .concat(table.getColData(col1).stream(), table.getColData(col2).stream())
                 .map(s -> (String) s)
                 .collect(Collectors.toList());

Я рекомендую вам более короткий и читаемый способ, который использует Stream::flatMap:

List<String> c = Stream.of(table.getColData(col1), table.getColData(col2))
                       .flatMap(list -> list.stream().map(s -> (String) s))
                       .collect(Collectors.toList());

Результат зависит от того, что именно возвращает метод getColData и можно ли преобразовать в String (@Eugene).

3
Nikolas 21 Авг 2018 в 13:56

Самый простой:

Stream.of(col1, col2)
      .map(table::<String>getColData)
      .flatMap(List::stream)
      .collect(Collectors.toList());

Поскольку ваш метод getColData возвращает T, вы можете указать тип T, используя свидетель типа <String>. Остальным является синтаксис Java для ссылок на методы.

Кроме того, использование дженериков может быть подвергнуто сомнению здесь. Это эквивалентно

public List<Object> getColData(final String col)

И приведение вашего списка к списку String:

Stream.of(col1, col2)
      .map(table::getColData)
      .map(o -> (String) o)
      .flatMap(List::stream)
      .collect(Collectors.toList());
3
Alex M 21 Авг 2018 в 17:10

Самый простой подход - просто добавить универсальный аргумент в метод, используя <>

Stream.concat(
        table.<String>getColData(col1).stream(),
        table.<String>getColData(col2).stream())
    .collect(toList());
1
killjoy 21 Авг 2018 в 14:01
51949552