Как ссылаться на результат операции Redu () в Java 8? - PullRequest
0 голосов
/ 02 февраля 2019

Я пытался написать mkString функцию на Java8, а-ля Scala, полезную mkString, и столкнулся с двумя проблемами, с которыми я мог бы помочь:

  1. ЯНевозможно сделать первый аргумент mkString универсальной ссылкой на коллекцию, например Collection<Object> c, и вызвать вызывающих для ЛЮБОГО типа коллекции.

  2. Невозможно сослаться на возвращенный результат reduce()для доступа к длине результата, чтобы удалить дополнительный ведущий разделитель.

Вот код:

public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    System.out.println(mkString(numbers, ","));

}

public static String mkString(Collection<Integer> c, String sep) {
    return c.stream()
            .map(e -> String.valueOf(e))
            .reduce("", (a, b) -> a + sep + b)
            .substring(1, <<>>.length);
}

Ответы [ 5 ]

0 голосов
/ 03 февраля 2019

Любой тип коллекции в java означает Collection<?>, что семантически совпадает с Collection<T> (в вашем случае), говорят, что если параметр типа используется только один раз), он можетсмело заменять подстановочным знаком.Но, так как вы хотите иметь возможность объединять любую коллекцию, вы должны также попросить вызывающих абонентов предоставить Function, который будет преобразовывать этот тип в строковое представление, таким образом, ваш метод станет:

public static <T> String mkString(Collection<T> c,
                                  Function<T, ? extends CharSequence> mapper,
                                  String sep) {
    return c.stream()
            .map(mapper)
            .collect(Collectors.joining(sep));

}
0 голосов
/ 03 февраля 2019

Вы можете использовать String.join с универсальным типом:

public static <T> String mkString(Collection<T> c, String sep) {
    return String.join(sep, c.stream()
                             .map(e -> String.valueOf(e))
                             .collect(Collectors.toList()));
}

Здесь это в действии как со строками, так и с другими объектами.

0 голосов
/ 02 февраля 2019

Вы можете сделать это как:

public static <T>  String mkString(Collection<T> c, String sep) { // generic impl
    return c.stream()
            .map(String::valueOf)
            .reduce("", (a, b) -> a + sep + b)
            .substring(1); // substring implementation to strip leading character
}
0 голосов
/ 02 февраля 2019

Обратите внимание, что если вы делаете это не для самообразования, а для фактического использования его в каком-то производственном коде, вы можете рассмотреть встроенный Collectors.joining сборщик:

String result = numbers.stream()
    .map(Object::toString)
    // or
    //   .map(x -> x.toString())  // exactly the same
    // or
    //   .map(String::valueOf)    // handles nulls by turning them to the string "null"
    .collect(Collectors.joining(","));

Имеет несколько перегрузок, аналогично Scala mkString.Тем не менее, этот сборщик принимает только CharSequence s, поэтому вам необходимо явно преобразовать значения в строки как отдельный шаг map.

Кроме того, существует метод String.join, который также работает для коллекции CharSequence с.Если у вас есть один из них (например, List<String>), может быть удобнее использовать этот метод, чем сначала преобразовывать коллекцию в поток:

List<String> strings = ...;

String result = String.join(",", strings);

// vs

String result = strings.stream().collect(Collectors.joining(","))
0 голосов
/ 02 февраля 2019

Если я правильно помню мой java, вы можете объявить тип аргумента как Collection<?>, чтобы иметь возможность передавать коллекцию любых объектов.

Что касается откусывания разделителя, я думаю, просто .substring(1) сделает то, что вы хотите.

...