Удаление перегруженного метода в Java - PullRequest
3 голосов
/ 09 ноября 2019

Есть 2 перегруженных метода.
Каждый из этих методов преобразует список одного типа в список другого типа. Но первый метод использует компаратор.

class SomeClass {
    public static <T, G> List<G> toListOfNewType(List<T> inputList,
                                                 Function<T, G> mapperFunction, 
                                                 Comparator<? super G> comparator) {
           return Stream.ofNullable(inputList)
                        .flatMap(List::stream)
                        .map(mapperFunction)
                        .sorted(comparator)
                        .collect(Collectors.toList());
    }
    public static <T, G> List<G> toListOfNewType(List<T> inputList,
                                                 Function<T, G> mapperFunction) {
           return Stream.ofNullable(inputList)
                        .flatMap(List::stream)
                        .map(mapperFunction)
                        .collect(Collectors.toList());
    }
}

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

Другими словами, как сделать первую работу без компаратора?

Ответы [ 5 ]

3 голосов
/ 09 ноября 2019

Используйте оператор if для проверки null:

public static <T, G> List<G> toListOfNewType(List<T> inputList,
                                             Function<T, G> mapperFunction,
                                             Comparator<? super G> comparator) {
    Stream<G> stream = Stream.ofNullable(inputList)
            .flatMap(List::stream)
            .map(mapperFunction);
    if (comparator != null)
        stream = stream.sorted(comparator);
    return stream.collect(Collectors.toList());
}

public static <T, G> List<G> toListOfNewType(List<T> inputList,
                                             Function<T, G> mapperFunction) {
    return toListOfNewType(inputList, mapperFunction, null);
}
2 голосов
/ 11 ноября 2019

В то время как я поддерживаю цель устранения дублирования кода на стороне реализации, я рассматриваю назначение специального значения для null вместо очистки перегруженных методов, шаг в неправильном направлении.

У вас все еще может быть дваметоды для удобства вызывающего без дублирования кода в реализации, например:

public static <T, G> List<G> toListOfNewType(List<T> inputList,
                                             Function<T, G> mapperFunction,
                                             Comparator<? super G> comparator) {
  List<G> resultList = toListOfNewType(inputList, mapperFunction);
  if(!resultList.isEmpty()) resultList.sort(comparator);
  return resultList;
}
public static <T, G> List<G> toListOfNewType(List<T> inputList,
                                             Function<T, G> mapperFunction) {
  return inputList==null? Collections.emptyList():
    inputList.stream().map(mapperFunction).collect(Collectors.toCollection(ArrayList::new));
}

Я бы даже подумал об отказе от поддержки списка ввода null, так как это приводит только к сокрытию проблем вместо их решения. .

Альтернативой может быть:

public static <T, G> List<G> toListOfNewType(List<T> inputList,
                                             Function<T, G> mapperFunction,
                                             Comparator<? super G> comparator) {
  return toListOfNewTypeImpl(inputList, mapperFunction, s -> s.sorted(comparator));
}
public static <T, G> List<G> toListOfNewType(List<T> inputList,
                                             Function<T, G> mapperFunction) {
  return toListOfNewTypeImpl(inputList, mapperFunction, UnaryOperator.identity());
}
private static <T, G> List<G> toListOfNewTypeImpl(List<T> inputList,
                                                  Function<T, G> mapperFunction,
                                                  UnaryOperator<Stream<G>> lastOp) {
  return lastOp.apply(inputList.stream().map(mapperFunction)).collect(Collectors.toList());
}
1 голос
/ 10 ноября 2019

В моей команде было бы интересно также спросить о некотором обзоре кода ... Проблема здесь в том, что если вы разрешите nullable Comparator, то вы немного побьете цель. argument, то есть Comparator , а - null, является совершенно допустимым значением естественного порядка сортировки, что означает, что это совершенно верно:

List<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);

Collections.sort(list, null);

Даже если ваша внутренняя реализация не разрешит это как есть, это означает:

List.of(4, 3, 2)
     .stream()
     .sorted(null)
     .forEachOrdered(System.out::println);

выдаст NullPointerException.

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

ИМХО не так уж много кода для "дублирования", и вы могли бы принудить пользователейпередать Function, который возвращает «что-то», то есть Comparable, выполнив:

public static <T, G extends Comparable<? extends G>> List<G> sortedToListOfNewType(
    List<T> inputList,
    Function<T, G> mapperFunction) {

    return Stream.ofNullable(inputList)
                 .flatMap(List::stream)
                 .map(mapperFunction)
                 .sorted()
                 .collect(Collectors.toList());
}

public static <T, G> List<G> toListOfNewType(
    List<T> inputList,
    Function<T, G> mapperFunction) {

    return Stream.ofNullable(inputList)
                 .flatMap(List::stream)
                 .map(mapperFunction)
                 .collect(Collectors.toList());
}

Недостатком является то, что 1) дублирующий код - что вы пытаетесь избежать во всех смыслах, кажется, 2) они могутНе следует перегружать методы - поскольку стирание одинаково и компилятор не допустит этого.

Но, как уже говорилось, этот подход очень субъективен.

1 голос
/ 09 ноября 2019

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

public static <T, G> List<G> toListOfNewType(List<T> inputList, Function<T, G> mapperFunction) {
    return toListOfNewType(inputList, mapperFunction, (a, b) -> 0);
}
0 голосов
/ 10 ноября 2019

Я не думаю, что есть простой способ сделать это, или я не знаю. Но если вы хотите попробовать мою библиотеку: abacus-util , вот что вы можете сделать:

StreamEx.of(inputList)
    .map(mapperFunction)
    .__(s -> comparator == null ? s : s.sort(comparator))
    .toList()
...