【问题标题】:Removing overloaded method in Java删除Java中的重载方法
【发布时间】:2019-11-09 18:13:46
【问题描述】:

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

如您所见,大部分行都是重复的。如何摆脱第二种方法,以便将 null 作为比较器传递给第一种方法不会破坏它?

换句话说,如何在没有比较器的情况下使第一个工作?

【问题讨论】:

  • 包括null 支票?

标签: java java-8 java-stream comparator


【解决方案1】:

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

【讨论】:

  • 可能会使用第二种方法private 并记录Comparator 可能为空。尽管这具有误导性,至少对我而言。 nullComparator 可以表示按自然顺序排序
  • @Eugene 为什么第二种方法应该是private?那么没有人会叫它。 --- 至于文档,这完全取决于 OP 来决定是否需要。
  • 实际上为什么要保留它?如果您记录第三个参数的目的,则根本不需要该方法。不是Stream::ofNullablejava-9吗?
  • @Eugene 我保留了重载以表明您可以保留它而不会出现重复的行,这似乎是 OP 的主要问题。我保留它是因为在 java 中重载忽略可选参数很常见(参见例如流 API)。我保留了它,以便 OP 知道可以选择。 OP可以选择保留或不保留。 --- Java 9 与什么有什么关系?这是问题中的代码。如果您在标记 java-8 时使用 Java 9 方法遇到 OP 问题,您应该就该问题向 OP 发表评论,不要责怪答案。
  • 我认为 API 如何向客户端公开是一个选择问题。但是使用当前的方法,设计看起来更像public static &lt;T, G&gt; List&lt;G&gt; toListOfNewType(List&lt;T&gt; inputList, Function&lt;T, G&gt; mapperFunction, @Nullable Comparator&lt;? super G&gt; comparator)。另一方面,Comparator 可能是用户的@NonNull,并在这种情况下重定向它们以使用重载方法。 (只是一个意见。)......我认为Java版本在这里并不重要@Eugene。
【解决方案2】:

虽然我的第二个目标是在实现方面消除代码重复,但我认为给 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());
}

【讨论】:

  • 我认为给null 赋予一个特殊的含义,而不是明确的重载方法是朝着错误方向迈出的一步 +1。当然在建议中大量使用UnaryOperator
【解决方案3】:

我可能只是用非常小的输入对其进行了测试(当然,即使在不需要时,执行元素比较的效率也较低),但可能这样做:

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

【讨论】:

  • 如需进一步确认,请咨询this question.
  • 这是可能的,但会产生一些不必要的开销,因为实现不了解排序操作已过时。
【解决方案4】:

在我的团队中询问一些代码审查也是一件有趣的事情......这里的问题是,如果你允许 nullable Comparator 你有点违背目的。 argumentComparator andnull自然顺序 排序的完全有效含义,这意味着这是完全有效的:

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

Collections.sort(list, null);

即使您的 internal 实现不允许它按原样进行,这意味着:

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) 这些不能是重载的方法——因为擦除是相同的,编译器不允许这样做。

但是,如上所述,这种方法非常主观。

【讨论】:

  • 感谢您的回答。我对允许 null 作为比较器有同样的感觉。因此,我可能会留下这两种方法,因为通过允许 null 来混淆调用者,而 Stream 类中的排序方法不允许,这可能是一个坏主意。但另外,我决定添加一个过滤器来消除输入列表中的空值。
  • @KyleBak 当然,如果您可以不允许以空列表开头,那也不错;但我知道这并不总是可能的。
【解决方案5】:

我认为没有简单的方法可以做到这一点,或者我不知道。但如果你想试试我的库:abacus-util,你可以这样做:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-02
    • 1970-01-01
    • 2014-01-04
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    相关资源
    最近更新 更多