13

I often need to iterate through a List starting at the second element. For example here is a column:

List<String> column = Arrays.asList("HEADER", "value1", "value2", "value3");

I need to print only values.

I see three approaches:

  1. Using sublist:

    for (String s : column.subList(1, column.size())) {
        System.out.println(s);
    }
    
  2. Using ListIterator

    for (ListIterator<String> iter = column.listIterator(1); iter.hasNext(); ) {
        System.out.println(iter.next());
    }
    
  3. Using index

    for (int i = 1; i < column.size(); i++) {
        System.out.println(column.get(i));
    }
    

What is the most preferred one considering readability, best practices and performance?

In my opinion sublist solution is more readable, but I rarely saw it in practice. Does it have any significant deficiencies comparing to index solution?

Evgeny Kharitonov
  • 947
  • 11
  • 12
  • All are ok, I would prefer them in exact the sequence you gave. The answer with streams is ok, too. Yet it is not really better readable. – CoronA Dec 22 '17 at 07:42

3 Answers3

11

If you use Java 8 or above you can use:

column.stream().skip(1).forEach((c) -> System.out.println(c))
senjin.hajrulahovic
  • 2,961
  • 2
  • 17
  • 32
5

This really boils down to (almost) "personal style" only.

You should simply pick what works best for you/your team.

Option 3 seems to be the one that comes with the least overhead - options 1 and 2 both create new "intermediate" objects (the sublist respectively the iterator). And just to be precise: sublist() doesn't create a new list and populate that - it boils down to a new Sublist object that simply "knows" about the boundaries within the larger parent list.

But: as soon as we consider lists that are not supporting random access to list elements (think linked lists for example) then option 3 results in a lot of performance cost compared to the others.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • option 1 doesn't create a new object, just a view of the original list would be returned – zaerymoghaddam Dec 22 '17 at 07:42
  • And that **view** sublist object isn't a new object? But I edited my answer to be more precise ;-) – GhostCat Dec 22 '17 at 07:42
  • Yeah, you're right. I was more thinking about the actual object reference that would be used as the underlying list ;) – zaerymoghaddam Dec 22 '17 at 07:43
  • 1
    Yet option 3 depends on a random access list. `LinkedList` will be expensive with option3. – CoronA Dec 22 '17 at 07:46
  • 1
    Option 3 will have awful performance if the list is not RandomAccess, though. And wouldn't be safe if the list is a concurrent list accessed from several threads. Not the case here, but an iterator-based iteration is safer and fast in general. – JB Nizet Dec 22 '17 at 07:46
  • @CoronA and JB are both correct ... simply forgot about that. Updated the answer accordingly. – GhostCat Dec 22 '17 at 08:02
1

It's more a matter of personal preferences. The sublist method doesn't return a new object, just a view on top of the current list, so it doesn't have any memory overhead. I think the readability is the only criteria to decide about this and the last option is the most readable solution and doesn't need to call any extra method (e.g. iterator, sublist, etc.)

zaerymoghaddam
  • 3,037
  • 1
  • 27
  • 33