Skip to content

Implement boxing wrappers for primitive collections. #1408

@motlin

Description

@motlin

Sometimes, one may want to pass a primitive collection into a method that takes a JCF interface. In cases like this, users must transform the primitive collection into an object collection to proceed.

public static void printAll(List<?> list)
{
    System.out.println("list = " + Iterate.makeString(list, ", "));
}


public static void main(String[] args)
{
    MutableIntList list = IntLists.mutable.with(1, 2, 3);
    printAll(list.collect(Integer::valueOf));
}

One option would be to make our primitive collections implement JCF interfaces. Fastutils does this; for example its IntArrayList implements List<Integer>

The downside is that it's very easy to accidentally cause boxing by using the primitive collection inside an enhanced for-loop.

A compromise that I believe would be pragmatic would be to implement a boxing wrappers for primitive collections, and a new method boxed(). If it existed, the example above would become:

    printAll(list.boxed());

The boxed() method would take O(1) time and space since it returns a wrapper.

To prove the idea, I wrote one wrapper. If we like the idea, we'd need to code generate it for all the primitives, and expand the functionality from just lists to sets and maps.

public class BoxedMutableIntList
        extends AbstractMutableList<Integer>
        implements MutableList<Integer>, RandomAccess
{
    private final MutableIntList delegate;

    public BoxedMutableIntList(MutableIntList delegate)
    {
        this.delegate = Objects.requireNonNull(delegate);
    }

    @Override
    public int size()
    {
        return this.delegate.size();
    }

    @Override
    public boolean isEmpty()
    {
        return this.delegate.isEmpty();
    }

    @Override
    public boolean contains(Object o)
    {
        return o instanceof Integer && this.delegate.contains((Integer) o);
    }

    @Override
    public boolean add(Integer integer)
    {
        return this.delegate.add(integer.intValue());
    }

    @Override
    public boolean remove(Object o)
    {
        return o instanceof Integer && this.delegate.remove((Integer) o);
    }

    @Override
    public boolean addAll(int index, Collection<? extends Integer> c)
    {
        return this.delegate.addAllAtIndex(index, c.stream().mapToInt(Integer::intValue).toArray());
    }

    @Override
    public void clear()
    {
        this.delegate.clear();
    }

    @Override
    public Integer get(int index)
    {
        return this.delegate.get(index);
    }

    @Override
    public Integer set(int index, Integer element)
    {
        return this.delegate.set(index, element.intValue());
    }

    @Override
    public void add(int index, Integer element)
    {
        this.delegate.addAtIndex(index, element.intValue());
    }

    @Override
    public Integer remove(int index)
    {
        return this.delegate.removeAtIndex(index);
    }

    @Override
    public int indexOf(Object o)
    {
        return o instanceof Integer ? this.delegate.indexOf((Integer) o) : -1;
    }

    @Override
    public int lastIndexOf(Object o)
    {
        return o instanceof Integer ? this.delegate.lastIndexOf((Integer) o) : -1;
    }

    @Override
    public MutableList<Integer> subList(int fromIndex, int toIndex)
    {
        return this.delegate.subList(fromIndex, toIndex).boxed();
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions