Removing overloaded method in Java

旧城冷巷雨未停 提交于 2019-12-10 18:22:33

问题


There are 2 overloaded methods.
Each of these methods converts a list of one type to a list of a different type. But the first method uses a comparator.

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());
    }
}

As you can see, most of the lines are duplicated. How can I get rid of the second method so that passing null to the first as a comparator will not break it?

In other words, how to make the first work without a comparator?


回答1:


Use an if statement to check for 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:


While I second the goal of removing code duplication on the implementation side, I consider assigning a special meaning to null instead of clear overloaded methods a step into the wrong direction.

You can still have two methods for the caller's convenience with no code duplication in the implementation, e.g.:

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));
}

I would even consider dropping the support for a null input list, as it only leads to hiding problems instead of solving them.

An alternative would be:

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());
}



回答3:


I might just have tested it with a very small input (and of course less efficient for performing element comparisons even when not required), but possibly this could do it :

public static <T, G> List<G> toListOfNewType(List<T> inputList, Function<T, G> mapperFunction) {
    return toListOfNewType(inputList, mapperFunction, (a, b) -> 0);
}



回答4:


This would be a interesting thing to ask in my team over some code review too... The problem here is that if you allow a nullable Comparator you are defeating the purpose a bit. An argument that is a Comparator and is null is perfectly valid meaning of a natural order sort, meaning this is perfectly valid:

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

Collections.sort(list, null);

Even if your internal implementation would not allow it as it is, meaning this:

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

would throw a NullPointerException.

So unless you clearly document what your intention is supposed to be for this method, users might be confused (I would).

IMHO it's not a lot of code to "duplicate" and you could enforce that users pass a Function that returns "something" that is Comparable by doing:

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());
}

The downside is that 1) duplicate code - that you try to avoid at all means it seems 2) these can not be overloaded methods - since the erasure is the same and the compiler would not allow this.

But, as said, this approach is very subjective.




回答5:


I don't think there is an easy way to do that or I don't know. But if you would like to try my library: abacus-util, here is what you can do:

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


来源:https://stackoverflow.com/questions/58782150/removing-overloaded-method-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!