Reputation: 8179
Alright, so I have a function like
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)
);
}
(EDIT: Note: the UnorderedList
here, is Vaadin's implementation of an html <ul>
tag, I'm not trying to get a java list.)
This will trigger a warning when you call it with an array saying that it's unclear whether you want to treat the array itself as a single element or as a container for the elements.
Don't immediately see an elegant way out of this. I like neither of these:
Object[]
Object...
into Collection<Object>
Is there an annotation or something that would let the compiler know to always resolve arrays to vararg calls on annotated methods? (On the method declaration, not the call sites.)
Upvotes: 1
Views: 253
Reputation: 298233
You can overload the method:
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)
);
}
Then, a call with an existing array will end up at newUnorderedList(Object[] items)
whereas an actual varargs call would end up at newUnorderedList(Object first, Object... other)
, even when only one argument has been specified, as long as that argument is not an array. Since the single argument is supposed to be either, a String
or Component
, this is not a problem.
The only possibility which has been lost with these two methods, is the ability to call the method without an argument. If this is a problem, you need to add another overload:
public static UnorderedList newUnorderedList() {
return newUnorderedListImpl(Stream.empty());
}
Upvotes: 5
Reputation: 4044
From your question, I guess that you want to do the following:
Object [] items = new Object [x];
items [0] = new Object [] {"Object1", "Object2", "Object3"};
var result = newUnorderedList( items );
This will treat the array with the String as a single item, causing the exception, while calling
var result = newUnorderedList( items [0] );
would return 3 elements for result
.
There is no annotation that forces the handling of a single array as a single item instead of a list of items. Have fun with a signature like this:
Object function( Object [] ... );
Upvotes: 0
Reputation: 2416
You're making an UnorderedList the wrong way.
Assuming it's a collection:
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));
Upvotes: 0