【问题标题】:Forcing call with array to resolve as varargs invocation强制使用数组调用以解析为可变参数调用
【发布时间】:2020-03-30 11:39:41
【问题描述】:

好的,所以我有一个类似的功能

public static UnorderedList newUnorderedList(Object... items) {
    return new UnorderedList(
        stream(items)
            .peek(e -> checkNotNull(e, "Cannot create null list item"))
            .map(e -> {
                if (e instanceof Component) return newListItem((Component) e);
                if (e instanceof String) return newListItem((String) e);
                throw new IllegalArgumentException("List item must be String or Component but is neither: " + e.getClass().getName());
            }).toArray(ListItem[]::new)
    );
}

编辑:注意:这里的UnorderedList,是Vaadin 对html <ul> 标签的实现,我不是要获取java 列表。)

当你用一个数组调用它时,这会触发一个警告,说不清楚你是将数组本身视为单个元素还是元素的容器。

不要立即看到摆脱这种情况的优雅方法。这两个我都不喜欢:

  • 始终转换为Object[]
  • Object...变成Collection<Object>

是否有注释或其他东西可以让编译器知道始终将数组解析为对带注释的方法的可变参数调用? (在方法声明上,而不是调用站点。)

【问题讨论】:

  • 什么是UnorderedList,为什么不创建一个返回无序列表的收集器?
  • 你试过用Arrays.stream(items)
  • @lscoughlin 抱歉,我认为这无关紧要。 UnorderedList 是 Vaadin 对 html <ul> 标签的实现。
  • @LazarPetrovic 到底要做什么?我已经在 stream(items) 使用它了。

标签: java casting jvm variadic-functions type-inference


【解决方案1】:

你可以重载方法:

public static UnorderedList newUnorderedList(Object first, Object... other) {
    return newUnorderedListImpl(Stream.concat(Stream.of(first), Arrays.stream(other)));
}
public static UnorderedList newUnorderedList(Object[] items) {
    return newUnorderedListImpl(Arrays.stream(items));
}
private static UnorderedList newUnorderedListImpl(Stream<?> items) {
    return new UnorderedList(
        items
            .peek(e -> checkNotNull(e, "Cannot create null list item"))
            .map(e -> {
                if (e instanceof Component) return newListItem((Component) e);
                if (e instanceof String) return newListItem((String) e);
                throw new IllegalArgumentException("List item must be String or Component but is neither: " + e.getClass().getName());
            }).toArray(ListItem[]::new)
    );
}

然后,使用现有数组的调用将结束于newUnorderedList(Object[] items),而实际的可变参数调用将结束于newUnorderedList(Object first, Object... other),即使只指定了一个参数,只要该参数不是数组。由于单个参数应该是StringComponent,所以这不是问题。

这两种方法失去的唯一可能性是在没有参数的情况下调用方法的能力。如果这是一个问题,您需要添加另一个重载:

public static UnorderedList newUnorderedList() {
    return newUnorderedListImpl(Stream.empty());
}

【讨论】:

  • 一个有趣的解决方案。您能否解释一下为什么这不会遇到与varargs 方法相同的问题? java 在决定我是要调用带有数组参数的方法还是要调用带有对象参数和额外空数组的方法时,不应该同样麻烦吗?
  • 当你有一个方法m(Object)和一个方法m(Object[])并用数组调用m时,方法m(Object[])优先,这是旧的“调用最具体的方法”规则,甚至早在可变参数被添加到 Java 之前就已经存在。事实上,当存在另一个没有可变参数的匹配方法时,Java 甚至不会考虑可变参数方法。如果你想打电话给newUnorderedList(anObject, anArray),你现在会遇到和以前一样的问题,但是这个用法不在你的愿望清单上,所以如果有人想这样使用它,他们必须忍受需要消歧。
【解决方案2】:

您以错误的方式制作 UnorderedList。

假设它是一个集合:

    Object[] objects = new Object[]{1, "hello", "there", "george"};
    LinkedList<AtomicReference<?>> list = Arrays.stream(objects)
            .filter(Objects::nonNull)
            .map(e -> {
                if (e instanceof Integer) return new AtomicReference<>(e);
                if (e instanceof StringBuilder) return new AtomicReference<>(e);
                throw new IllegalArgumentException("PAIN");
            })
            .collect(Collectors.toCollection(LinkedList::new));

【讨论】:

  • 如果我们假设 UnorderedList 对于基于数组的类型来说只是一个坏名字?顺便说一句,代码主要构建了一个数组,它是UnorderedList的构造函数的参数……
  • 你猜错了。这是 Vaadin 对 html &lt;ul&gt; 标签的实现。它接收 Components 的可变参数,因此是数组。将该信息添加到问题中。
【解决方案3】:

根据您的问题,我猜您想要执行以下操作:

Object [] items = new Object [x];
items [0] = new Object [] {"Object1", "Object2", "Object3"};
var result = newUnorderedList( items );

这会将带有String的数组视为单个项目,导致异常,同时调用

var result = newUnorderedList( items [0] );

将为result 返回 3 个元素。

没有注释强制将单个数组作为单个项目而不是项目列表进行处理。享受这样的签名:

Object function( Object [] ... );

【讨论】:

  • 恰恰相反,我想传递一个数组并将其视为可变参数。这里的问题是Object[]Object,因此该函数(根据警告)不确定我希望它以哪种方式处理,除非我将其转换为任何一种。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2018-04-22
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多