98

How do I get an array slice of an ArrayList in Java? Specifically I want to do something like this:

ArrayList<Integer> inputA = input.subList(0, input.size()/2);
// where 'input' is a prepouplated ArrayList<Integer>

So I expected this to work, but Java returns a List - so it's incompatible. And when I try to cast it, Java won't let me. I need an ArrayList - what can I do?

4
  • 4
    Why do you insist on using an ArrayList? I think you may lack a little bit of understanding how interfaces work because List and ArrayList are not “incompatible”—ArrayList implements List, and List probably contains all necessary methods you need. Commented Sep 26, 2009 at 11:59
  • 7
    I insist on using ArrayList because its an inteview question with a rigid method prototype. I clearly do have a lack of understanding, because subList is supposed to return a List type, and yet I can't cast the returned List to ArrayList. So you tell me man.. Commented Sep 26, 2009 at 20:48
  • 8
    It's entirely possible that he needs an ArrayList because he then needs to call a method with it which accepts an ArrayList. Arguably such a method is poorly designed and should accept List instead, but such situations can arise not only in interview questions but in code written by others that one can't just go and change. Co-workers and libraries aren't always perfect. Commented Jan 12, 2012 at 20:03
  • See stackoverflow.com/questions/1279476/… Commented Jul 22, 2014 at 16:46

5 Answers 5

148

In Java, it is good practice to use interface types rather than concrete classes in APIs.

Your problem is that you1 are using ArrayList (probably in lots of places) where you should really be using List. As a result you created problems for yourself with an unnecessary constraint that the list is an ArrayList.

This is what your code should look like:

List input = new ArrayList(...);

public void doSomething(List input) {
   List inputA = input.subList(0, input.size()/2);
   ...
}

this.doSomething(input);

1 - Based on your comments, "you" was actually someone else ... who set this problem in an interview question. It is possible that this was actually a trick question, designed to see how you would cope with creating a (real) slice of an ArrayList that was a assignment compatible with ArrayList.


Your proposed solution to the problem was/is this:

new ArrayList(input.subList(0, input.size()/2))

That works by making a copy of the sublist (slice) returned by the sublist call. The resulting ArrayList is not a slice in the normal sense. It is a distinct list. Mutating this list does not change the original list or vice-versa. Furthermore, if the sublist is big, then making the copy will be expensive.


If you are constrained by APIs that you cannot change, such that you have to declare inputA as an ArrayList, you might be able to implement a custom subclass of ArrayList in which the subList method returns a subclass of ArrayList. However:

  1. It would be a lot of work to design, implement and test.
  2. You have now added significant new class to your code base, possibly with dependencies on undocumented aspects (and therefore "subject to change") aspects of the ArrayList class.
  3. You would need to change relevant places in your codebase where you are creating ArrayList instances to create instances of your subclass instead.

The "copy the array" solution is more practical ... bearing in mind that these are not true slices.

Sign up to request clarification or add additional context in comments.

3 Comments

Actually, subList does not make a copy; it returns a view into the original list (docs.oracle.com/javase/6/docs/api/java/util/…)
Actually @Matthew, I am referring to the OP's self-answer where he does this: new ArrayList(input.subList(0, input.size()/2))
+1 for this phrase: In Java, it is good practice to use interface types rather than concrete classes in APIs.
9

I have found a way if you know startIndex and endIndex of the elements one need to remove from ArrayList

Let al be the original ArrayList and startIndex,endIndex be start and end index to be removed from the array respectively:

al.subList(startIndex, endIndex + 1).clear();

Comments

6

If there is no existing method then I guess you can iterate from 0 to input.size()/2, taking each consecutive element and appending it to a new ArrayList.

EDIT: Actually, I think you can take that List and use it to instantiate a new ArrayList using one of the ArrayList constructors.

3 Comments

Thats exactly what I did (posted my answer before I read your edit). Thanks : )
But that copies the List to make a new ArrayList.
@BT - For the record, that is not what the term "slice" normally means in this context.
3

Although this post is very old. In case if somebody is looking for this..

Guava facilitates partitioning the List into sublists of a specified size

List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
    List<List<Integer>> subSets = Lists.partition(intList, 3);

1 Comment

-3

This is how I solved it. I forgot that sublist was a direct reference to the elements in the original list, so it makes sense why it wouldn't work.

ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.