Define a fixed-size list in Java - java

Is it possible to define a list with a fixed size that's 100? If not why isn't this available in Java?

This should do it if memory serves:
List<MyType> fixed = Arrays.asList(new MyType[100]);

A Java list is a collection of objects ... the elements of a list. The size of the list is the number of elements in that list. If you want that size to be fixed, that means that you cannot either add or remove elements, because adding or removing elements would violate your "fixed size" constraint.
The simplest way to implement a "fixed sized" list (if that is really what you want!) is to put the elements into an array and then Arrays.asList(array) to create the list wrapper. The wrapper will allow you to do operations like get and set, but the add and remove operations will throw exceptions.
And if you want to create a fixed-sized wrapper for an existing list, then you could use the Apache commons FixedSizeList class. But note that this wrapper can't stop something else changing the size of the original list, and if that happens the wrapped list will presumably reflect those changes.
On the other hand, if you really want a list type with a fixed limit (or limits) on its size, then you'll need to create your own List class to implement this. For example, you could create a wrapper class that implements the relevant checks in the various add / addAll and remove / removeAll / retainAll operations. (And in the iterator remove methods if they are supported.)
So why doesn't the Java Collections framework implement these? Here's why I think so:
Use-cases that need this are rare.
The use-cases where this is needed, there are different requirements on what to do when an operation tries to break the limits; e.g. throw exception, ignore operation, discard some other element to make space.
A list implementation with limits could be problematic for helper methods; e.g. Collections.sort.

FixedSizeList
Yes,
The Apache Commons library provides the FixedSizeList class which does not support the add, remove and clear methods (but the set method is allowed because it does not modify the List's size). Ditto for FixedSizeList in Eclipse Collections. If you try to call one of these methods, your list remains the same size.
To create your fixed size list, just call
List<YourType> fixed = FixedSizeList.decorate(Arrays.asList(new YourType[100]));
You can use unmodifiableList if you want an unmodifiable view of the specified list, or read-only access to internal lists.
List<YourType> unmodifiable = java.util.Collections.unmodifiableList(internalList);

Yes. You can pass a java array to Arrays.asList(Object[]).
List<String> fixedSizeList = Arrays.asList(new String[100]);
You cannot insert new Strings to the fixedSizeList (it already has 100 elements). You can only set its values like this:
fixedSizeList.set(7, "new value");
That way you have a fixed size list. The thing functions like an array and I can't think of a good reason to use it. I'd love to hear why you want your fixed size collection to be a list instead of just using an array.

Typically an alternative for fixed size Lists are Java arrays. Lists by default are allowed to grow/shrink in Java. However, that does not mean you cannot have a List of a fixed size. You'll need to do some work and create a custom implementation.
You can extend an ArrayList with custom implementations of the clear, add and remove methods.
e.g.
import java.util.ArrayList;
public class FixedSizeList<T> extends ArrayList<T> {
public FixedSizeList(int capacity) {
super(capacity);
for (int i = 0; i < capacity; i++) {
super.add(null);
}
}
public FixedSizeList(T[] initialElements) {
super(initialElements.length);
for (T loopElement : initialElements) {
super.add(loopElement);
}
}
#Override
public void clear() {
throw new UnsupportedOperationException("Elements may not be cleared from a fixed size List.");
}
#Override
public boolean add(T o) {
throw new UnsupportedOperationException("Elements may not be added to a fixed size List, use set() instead.");
}
#Override
public void add(int index, T element) {
throw new UnsupportedOperationException("Elements may not be added to a fixed size List, use set() instead.");
}
#Override
public T remove(int index) {
throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
}
#Override
public boolean remove(Object o) {
throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
}
#Override
protected void removeRange(int fromIndex, int toIndex) {
throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
}
}

Create an array of size 100. If you need the List interface, then call Arrays.asList on it. It'll return a fixed-size list backed by the array.

If you want some flexibility, create a class that watches the size of the list.
Here's a simple example. You would need to override all the methods that change the state of the list.
public class LimitedArrayList<T> extends ArrayList<T>{
private int limit;
public LimitedArrayList(int limit){
this.limit = limit;
}
#Override
public void add(T item){
if (this.size() > limit)
throw new ListTooLargeException();
super.add(item);
}
// ... similarly for other methods that may add new elements ...

You can define a generic function like this:
#SuppressWarnings("unchecked")
public static <T> List<T> newFixedSizeList(int size) {
return (List<T>)Arrays.asList(new Object[size]);
}
And
List<String> s = newFixedSizeList(3); // All elements are initialized to null
s.set(0, "zero");
s.add("three"); // throws java.lang.UnsupportedOperationException

This should work pretty nicely. It will never grow beyond the initial size. The toList method will give you the entries in the correct chronological order. This was done in groovy - but converting it to java proper should be pretty easy.
static class FixedSizeCircularReference<T> {
T[] entries
FixedSizeCircularReference(int size) {
this.entries = new Object[size] as T[]
this.size = size
}
int cur = 0
int size
void add(T entry) {
entries[cur++] = entry
if (cur >= size) {
cur = 0
}
}
List<T> asList() {
List<T> list = new ArrayList<>()
int oldest = (cur == size - 1) ? 0 : cur
for (int i = 0; i < this.entries.length; i++) {
def e = this.entries[oldest + i < size ? oldest + i : oldest + i - size]
if (e) list.add(e)
}
return list
}
}
FixedSizeCircularReference<String> latestEntries = new FixedSizeCircularReference(100)
latestEntries.add('message 1')
// .....
latestEntries.add('message 1000')
latestEntries.asList() //Returns list of '100' messages

If you want to use ArrayList or LinkedList, it seems that the answer is no. Although there are some classes in java that you can set them fixed size, like PriorityQueue, ArrayList and LinkedList can't, because there is no constructor for these two to specify capacity.
If you want to stick to ArrayList/LinkedList, one easy solution is to check the size manually each time.
public void fixedAdd(List<Integer> list, int val, int size) {
list.add(val);
if(list.size() > size) list.remove(0);
}
LinkedList is better than ArrayList in this situation. Suppose there are many values to be added but the list size is quite samll, there will be many remove operations. The reason is that the cost of removing from ArrayList is O(N), but only O(1) for LinkedList.

The public java.util.List subclasses of the JDK don't provide a fixed size feature that doesn't make part of the List specification.
You could find it only in Queue subclasses (for example ArrayBlockingQueue, a bounded blocking queue backed by an array for example) that handle very specific requirements.
In Java, with a List type, you could implement it according to two scenarios :
1) The fixed list size is always both the actual and the maximum size.
It sounds as an array definition. So Arrays.asList() that returns a fixed-size list backed by the specified array is what you are looking for. And as with an array you can neither increase nor decrease its size but only changing its content. So adding and removing operation are not supported.
For example :
Foo[] foosInput= ...;
List<Foo> foos = Arrays.asList(foosInput);
foos.add(new Foo()); // throws an Exception
foos.remove(new Foo()); // throws an Exception
It works also with a collection as input while first we convert it into an array :
Collection<Foo> foosInput= ...;
List<Foo> foos = Arrays.asList(foosInput.toArray(Foo[]::new)); // Java 11 way
// Or
List<Foo> foos = Arrays.asList(foosInput.stream().toArray(Foo[]::new)); // Java 8 way
2) The list content is not known as soon as its creation. So you mean by fixed size list its maximum size.
You could use inheritance (extends ArrayList) but you should favor composition over that since it allows you to not couple your class with the implementation details of this implementation and provides also flexibility about the implementation of the decorated/composed.
With Guava Forwarding classes you could do :
import com.google.common.collect.ForwardingList;
public class FixedSizeList<T> extends ForwardingList<T> {
private final List<T> delegate;
private final int maxSize;
public FixedSizeList(List<T> delegate, int maxSize) {
this.delegate = delegate;
this.maxSize = maxSize;
}
#Override protected List<T> delegate() {
return delegate;
}
#Override public boolean add(T element) {
assertMaxSizeNotReached(1);
return super.add(element);
}
#Override public void add(int index, T element) {
assertMaxSizeNotReached(1);
super.add(index, element);
}
#Override public boolean addAll(Collection<? extends T> collection) {
assertMaxSizeNotReached(collection.size());
return super.addAll(collection);
}
#Override public boolean addAll(int index, Collection<? extends T> elements) {
assertMaxSizeNotReached(elements.size());
return super.addAll(index, elements);
}
private void assertMaxSizeNotReached(int size) {
if (delegate.size() + size >= maxSize) {
throw new RuntimeException("size max reached");
}
}
}
And use it :
List<String> fixedSizeList = new FixedSizeList<>(new ArrayList<>(), 3);
fixedSizeList.addAll(Arrays.asList("1", "2", "3"));
fixedSizeList.add("4"); // throws an Exception
Note that with composition, you could use it with any List implementation :
List<String> fixedSizeList = new FixedSizeList<>(new LinkedList<>(), 3);
//...
Which is not possible with inheritance.

You need either of the following depending on the type of the container of T elements you pass to the builder (Collection<T> or T[]):
In case of an existing Collection<T> YOUR_COLLECTION:
Collections.unmodifiableList(new ArrayList<>(YOUR_COLLECTION));
In case of an existing T[] YOUR_ARRAY:
Arrays.asList(YOUR_ARRAY);
Simple as that

To get a fixed-size list, you can simply use the Stream API. This will result in a fixed-size list :
List<Integer> list = Arrays.stream(new int[100])
.boxed()
.collect(Collectors.toList());
Or the old-fashioned way, This will result in a fixed-size list that is backed by the specified array:
List<Integer> list = Arrays.asList(new Integer[100]);

Yes is posible:
List<Integer> myArrayList = new ArrayList<>(100);
now, the initial capacity of myArrayList will be 100

Related

Reverse a generic collection in Java

I've got the following task:
"Declare a method, expecting a Collection and reverse it in your method. Return the same collection given, do not return a new collection!.
static <T> void reverse (Collection<T> collection)
Do not try to use Collections.reverse. It works only for a List, and not for collections"
My initial idea was something of the following:
public static <T> void reverse(Collection<T> collection){
int size = collection.size();
Iterator<T> iter = collection.iterator();
Iterator<T> iter2 = collection.iterator();
for (int i = 0; i < size / 2; i++) {
collection.add(iter.next());
iter2.remove();
}
}
But I keep getting weird exceptions:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at ReverseCollection.reverse(ReverseCollection.java:16)
at ReverseCollection.main(ReverseCollection.java:25)
Any idea how this should be done?
What you want to do cannot be done, since many Collection classes (for example HashSet) do not let you control the order.
The problem is that the order of elements in a general Collection is not defined. For example, think of a Set, which does not guarantee the order of the elements.
Since there is no ordering, it is hard to define what the reverse order is.
Whilst the task is generally impossible (e.g. for immutable collections, and collections which do not iterate in insertion order), you can reverse any collection in which insertion order is preserved and the optional clear and addAll are implemented as follows:
<T, C extends Collection<T>> C reverse(C in) {
// Copy the contents of the collection into a new list.
List<T> list = new ArrayList<>(in);
// Remove everything from the original container.
in.clear();
// Reverse the list.
Collections.reverse(list);
// Put everything back into the original container.
in.addAll(list);
// If addAll is not supported, but add is, you can do
// for (T t : list) { in.add(t); }
return in;
}
For collections where insertion order is not preserved, this may or may not result in a different ordering (e.g. it could be different for a HashSet; it would not be different for a TreeSet).

T[] toArray(T[] a) implementation

I am creating a SortedList class that implements List.
If I understand correctly, the method toArray(T[] a) takes an array of objects as a parameter and returns a sorted array of these objects.
In the java documentation we can read that if the Collection length is greater than the sortedList, a new array is created with the good size, and if the collection length is smaller than the sortedList, the object following the last object of the collection is set to null.
The project I am working on does not let me use null values in the sorted list, so I am implementing the method differently, using a new sortedList and the toArray() method:
public <T> T[] toArray(T[] a)
{
SortedList sort = new SortedList();
for(Object o : a)
{
sort.add(o);
}
return (T[])sort.toArray();
}
Would this be a good way to implement this method or should I expect errors using it like that?
Thank you for your time.
First a recommendation:
If you want SortedList to implement the List interface, it's a good idea to extend AbstractList instead of implementing List directly. AbstractList has already defined many of the necessary methods, including the one you're having problems with. Most List-implementations in the Java platform libraries also extend AbstractList.
If you still want to implement List directly, here is what the method is supposed to do:
Let a be the specified array.
If a is large enough, fill it with the elements from your SortedList (in the correct order) without caring about what was previously in a.
If there's room to spare in a after filling it, set a[size()] = null. Then the user will know where the list ends, unless the list contains null-elements.
If the list doesn't fit in a, create a new array of type T with the same size as the list, and fill the new one instead.
Return the array you filled. If you filled a, return a. If you made a new array, return the new array.
There are two reasons why this method is useful:
The array will not necessarily be of type Object, but of a type T decided by the user (as long as the type is valid).
The user may want to save memory and re-use an array instead of allocating more mamory to make a new one.
Here is how the Java Docs describe the method.
If you are implementing a "SortedList" class, it's probably in your best interest to maintain a sorted list internally, rather than relying on the toArray() method to sort them on the way out. In other words, users of the class may not use the toArray() method, but may instead use listIterator() to return an Iterator that is supposed to iterate over the elements of the list in the proper order.
Are you sure you need to implement List. It is often sufficient just to implement Iterable and Iterator.
public class SortedList<S extends Comparable<S>> implements Iterable<S>, Iterator<S> {
private final Iterator<S> i;
// Iterator version.
public SortedList(Iterator<S> iter, Comparator<S> compare) {
// Roll the whole lot into a TreeSet to sort it.
Set<S> sorted = new TreeSet<S>(compare);
while (iter.hasNext()) {
sorted.add(iter.next());
}
// Use the TreeSet iterator.
i = sorted.iterator();
}
// Provide a default simple comparator.
public SortedList(Iterator<S> iter) {
this(iter, new Comparator<S>() {
public int compare(S p1, S p2) {
return p1.compareTo(p2);
}
});
}
// Also available from an Iterable.
public SortedList(Iterable<S> iter, Comparator<S> compare) {
this(iter.iterator(), compare);
}
// Also available from an Iterable.
public SortedList(Iterable<S> iter) {
this(iter.iterator());
}
// Give them the iterator directly.
public Iterator<S> iterator() {
return i;
}
// Proxy.
public boolean hasNext() {
return i.hasNext();
}
// Proxy.
public S next() {
return i.next();
}
// Proxy.
public void remove() {
i.remove();
}
}
You can then do stuff like:
for ( String s : new SortedList<String>(list) )
which is usually all that you want because TreeSet provides your sortedness for you.

Is this an approach to create a read-only List in Java?

Thinking in java says:
To create a read-only List from AbstractList, you must implements get() and size().
It confused me, the code is below:
public class CountingIntegerList
extends AbstractList<Integer> {
private int size;
public CountingIntegerList(int size) {
this.size = size < 0 ? 0 : size;
}
public Integer get(int index) {
return Integer.valueOf(index);
}
public int size() { return size; }
public static void main(String[] args) {
List list = new CountingIntegerList(30);
}
}
Is list a read-only List? Why?
Ok, the answer is yes since I extend AbstractList and it throw UnsupportedOperationException if set or and is called. If I want to get a unmodifiableList, Collections.unmodifiableList() is a good choice. But remember, both of them are not deeply immutable:
List<StringBuilder> list = new ArrayList<StringBuilder>();
StringBuilder sb = new StringBuilder();
sb.append("hello");
list.add(sb);
System.out.println(list);
list = Collections.unmodifiableList(list);
sb.append("world");
System.out.println(list);
There is a flyweight pattern in CountingIntegerList. because everytime get() is called,it get caches from Integer, the source code of valueOf():
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
Is is right?
It's read-only (even immutable) because add will throw an UnsupportedOperationException as will remove.
AbstractList handles all the work of creating iterators,
computing hashcodes and equality for you. It's very helpful.
It's completely unnecessary to wrap in unmodifiableList.
Later you ask whether AbstractList is used mainly to create unmodifiable lists. Actually it is used to create any kind of random-access list. In my course in data structures, we use abstract classes such as this to save most of the work of implementing a list class. Even the Collection interface has 13 methods, all but two of which are implements by AbstractCollection.
There is the related class AbstractSequentialList that helps create lists that are not random access (such as linked lists).
because set throws an UnsupportedOperationException, if not implemented. See Api
you could wrap your List in an UnmodifiableList
List readOnlyList = Collections.unmodifiableList(yourList)
Pass the ArrayList into Collections.unmodifiableList()
Returns an unmodifiable view of the specified list. This method allows
modules to provide users with "read-only" access to internal lists.
Query operations on the returned list "read through" to the specified
list, and attempts to modify the returned list, whether direct or via
its iterator, result in an UnsupportedOperationException. The returned
list will be serializable if the specified list is serializable.
Similarly, the returned list will implement RandomAccess if the
specified list does.
This is tricky a bit. The list can not change and/or the elements also? ;)
StringBuilder builder = new StringBuilder();
builder.append("Hello");
List<StringBuilder> list = new ArrayList<StringBuilder>();
list.add(builder);
Collection<StringBuilder> canNotChange = Collections.unmodifiableCollection(list);
builder.append(" World");
System.out.println(canNotChange.iterator().next());

List with fast contains

I wonder if there's a List implementation allowing fast contains. I'm working with quite a long List and I can't switch to Set since I need the access by index. I can ignore the performance, which may be acceptable now and may or may not be acceptable in the future. I can create a HashSet and do all modifying operations on both, but doing it manually is quite boring and error prone.
I know that it's impossible to have a class working like both List and Set (because of the different equals semantics), but I wonder if there's List implementing RandomAccess and employing an HashSet for speeding up contains.
I know that it's impossible to have a class working like both List and Set
Have you tried LinkedHashSet? Technically it's a set but it preserves order which might be just enough for you. However access by index is linear and not built-in.
Other approach would be to wrap List with a custom decorator that both delegates to List and maintains a n internalSet for faster contains.
you can wrap a list and hashSet that combines best of both worlds
public class FastContainsList<T> extends AbstractSequentialList<T> implements RandomAccess{
//extending sequential because it bases itself of the ListIterator(int) and size() implementation
private List<T> list=new ArrayList<T>();
private Set<T> set=new HashSet<T>();
public int size(){
return list.size();
}
public boolean contains(Object o){//what it's about
return set.contains(o);
}
public ListIterator<T> listIterator(int i){
return new ConIterator(list.listIterator(i));
}
/*for iterator()*/
private ConIterator implements ListIterator<T>{
T obj;
ListIterator<T> it;
private ConIterator(ListIterator<T> it){
this.it = it
}
public T next(){
return obj=it.next();
}
public T previous(){
return obj=it.previous();
}
public void remove(){
it.remove();//remove from both
set.remove(obj);
}
public void set(T t){
it.set(t);
set.remove(obj);
set.add(obj=t);
}
public void add(T t){
it.add(t);
set.add(t);
}
//hasNext and hasPrevious + indexes still to be forwarded to it
}
}
What about a BiMap<Integer, MyClass>? This can be found in Guava
BiMap<Integer, MyClass> map = HashBiMap.create();
//store by index
map.put(1, myObj1);
//get by index
MyClass retrievedObj = map.get(1);
//check if in map
if ( map.containsValue(retrievedObj) ) {
//...
}
I know it doesn't implement the List interface. The major limitation here is that insertion and removal are not provided in the traditional List sense; but you didn't specifically say whether those were important to you.
Apache Commons TreeList should do the trick:
http://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/list/TreeList.html
You can maintain a List and Set. This will give you fast indexed lookup and contains (with a small overhead)
BTW: If your list is small, e.g. 10 entries, it may not make any difference to use a plain List.
I think a class that wraps a HashMap and List (as you said in your post) is probably the best best for fast contains and access.

Java: "cons" an item to a list

I have an Item which has a method List<Item> getChildren() (which returns an immutable list) and for each of the items I have, I need to create a list of the item followed by its children.
What's the quickest way to "cons" (in the Lisp/Scheme sense) my item to create a new immutable list? I can certainly do the following, but it seems wrong/wasteful:
public List<Item> getItemAndItsChildren(Item item)
{
if (item.getChildren.isEmpty())
return Collections.singletonList(item);
else
{
// would rather just "return cons(item, item.getChildren())"
// than do the following -- which, although straightforward,
// seems wrong/wasteful.
List<Item> items = new ArrayList<Item>();
items.add(item);
items.addAll(item.getChildren());
return Collections.unmodifiableList(items);
}
}
I'd change my requirements. In most cases, you don't need a List in your interface, an Iterable will do nicely. Here's the method:
public Iterable<Item> getItemWithChildren(Item item) {
return Iterables.unmodifiableIterable(
Iterables.concat(
Collections.singleton(item),
item.getChildren()
)
);
}
and here's the shortened version (with static imports):
return unmodifiableIterable(concat(singleton(item), item.getChildren()));
The ability to create a new immutable list by concatenating a head element to a tail that may be shared between other lists requires a singly-linked list implementation. Java doesn't provide anything like this out of the box, so your ArrayList solution is as good as anything.
It's also going to be relatively efficient, assuming that these lists are short-lived and you don't have tens of thousands of element in the list. If you do, and if this operation is taking a significant portion of your execution time, then implmenting your own single-linked list might be worthwhile.
My one change to improve your existing efficiency: construct the new list with a capacity (1 + size of old list).
You shouldn't need to special case an Item with no children.
public List<Item> getItemAndItsChildren(Item item)
{
List<Item> items = new ArrayList<Item>();
items.add(item);
items.addAll(item.getChildren());
return Collections.unmodifiableList(items);
}
Also, if you are looking to use a language that isn't verbose, then Java is a poor choice. I'm sure you can do what you like in far less code in Groovy and Scala which both run on the JVM. (Not to mention JRuby or Jython.)
It sounds like you're looking for something like a CompositeList, similar to the Apache Commons' CompositeCollection. An implementation could be as naive as this:
public class CompositeList<T> extends AbstractList<T>{
private final List<T> first, second;
public CompositeList(List<T> first, List<T> second) {
this.second = second;
this.first = first;
}
#Override
public T get(int index) {
if ( index < first.size() ) {
return first.get(index);
} else {
return second.get(index - first.size());
}
}
#Override
public int size() {
return first.size() + second.size();
}
}
And you could use it like this:
public List<Item> getItemAndItsChildren(Item item)
{
return Collections.unmodifiableList(
new CompositeList<Item>(Collections.singletonList(item), item.getChildren()) );
}
But there are huge caveats that make such a class difficult to use...the main problem being that the List interface cannot itself mandate that it is unmodifiable. If you are going to use something like this you must ensure that clients of this code never modify the children!
I use these. (using guava's ImmutableList and Iterables)
/** Returns a new ImmutableList with the given element added */
public static <T> ImmutableList<T> add(final Iterable<? extends T> list, final T elem) {
return ImmutableList.copyOf(Iterables.concat(list, Collections.singleton(elem)));
}
/** Returns a new ImmutableList with the given elements added */
public static <T> ImmutableList<T> add(final Iterable<? extends T> list, final Iterable<? extends T> elems) {
return ImmutableList.copyOf(Iterables.concat(list, elems));
}
/** Returns a new ImmutableList with the given element inserted at the given index */
public static <T> ImmutableList<T> add(final List<? extends T> list, final int index, final T elem) {
return ImmutableList.copyOf(Iterables.concat(list.subList(0, index), Collections.singleton(elem), list.subList(index, list.size())));
}
/** Returns a new ImmutableList with the given element inserted at the given index */
public static <T> ImmutableList<T> add(final List<? extends T> list, final int index, final Iterable<?extends T> elems) {
return ImmutableList.copyOf(Iterables.concat(list.subList(0, index), elems, list.subList(index, list.size())));
}
But none of them are efficient.
Example of prepending/consing an item to a list:
ImmutableList<String> letters = ImmutableList.of("a", "b", "c");
add(letters, 0, "d");
For more efficient immutable/persistent collections you should, as #eneveu points out, look at pcollections, although I have no idea what the quality of that library is.
pcollections is a persistent Java collection library you might be interested in. I bookmarked it a while ago, and haven't yet used it, but the project seems relatively active.
If you want to use Guava, you could use the unmodifiable view returned by Lists.asList(E first, E[] rest). It works with arrays, and its primary goal is to simplify the use of var-args methods. But I see no reason you couldn't use it in your case:
public List<Item> getItemAndItsChildren(Item item) {
return Lists.asList(item, item.getChildren().toArray());
}
The List returned is an unmodifiable view, but it may change if the source array is modified. In your case, it's not a problem, since the getChildren() method returns an immutable list. Even if it were mutable, the toArray() method supposedly returns a "safe" array...
If you want to be extra safe, you could do:
public ImmutableList<Item> getItemAndItsChildren(Item item) {
return ImmutableList.copyOf(Lists.asList(item, item.getChildren().toArray()));
}
Note that Lists.asList() avoids un-necessary ArrayList instantiation, since it's a view. Also, ImmutableList.copyOf() would delegate to ImmutableList.of(E element) when the children list is empty (which, similarly to Collections.singletonList(), is space-efficient).
You should instantiate your list with the exact number you will be putting into it to eliminate expansion copies when you add more.
List<Item> items = new ArrayList<Item>();
should be
List<Item> items = new ArrayList<Item>(item.getChildren() + 1);
otherwise what you are doing is about as idiomatic Java as you can get.
Another thing, is you might consider using Guava and its ImmutableList implementation rather than an Collections.unmodifiableList().
Unlike Collections.unmodifiableList(java.util.List), which is a view
of a separate collection that can still change, an instance of
ImmutableList contains its own private data and will never change.
ImmutableList is convenient for public static final lists ("constant
lists") and also lets you easily make a "defensive copy" of a list
provided to your class by a caller.

Categories