(I had been writing this before I received Max’s answer. Still...) >From a general point of vue I agree that declaring a LinkedList makes sense, when you want to stress the fact that you’re working with a sequential structure with which it’s cheap to add/remove/access elements at the beginning or end, but costly to retrieve one particular element in the middle. The unfortunate fact in Java is that the getFirst/Last and addFirst/Last methods are available only in the LinkedList concrete class, and not on an interface. Starting from Java 1.5 the Queue interface fills this gap and would probably be used instead.
That said, on this particular topic, one may raise the question whether the getNextKnuthElements methods should really return a sequential structure or just a list. Looking at the commit, most of the getLast method calls are used to test if the last returned element is a forced break. In some future this should disappear and be handled a different way (add a break /between/ blocks if there must be one). So I’m ok with Max’s change. And, still, congrats Max! It’s not the funniest of the jobs. Andreas Delmelle wrote: <snip/> > For anything that remains FOP-internal, using concrete implementations > does not only improve code-readability and -writability, but IIC, it > also generates more efficient byte-code in the end. At run-time, the > interpreter would spend slightly less time on determining the actual > implementation of a method to be used. > > For the above example, the interpreter originally only needed to check > the available implementations of getLast() (defined in the concrete > class LinkedList), while after the change, it would need to check those > of get() (defined in the List interface). Checking for the > implementations of interface methods is known to be slightly more > demanding than for class methods. > Also, if we always know that the concrete type of the List in question > is a LinkedList, index-based access is generally taken to be a bad idea. > list.getLast() is likely to outperform list.get(list.size() - 1), > especially if the lists grow large.... I really have to disagree here. In general I would be very reluctant to sacrifice code encapsulation to optimization, unless the gain in performance is significant. And on this particular point there’s absolutely no benefit. The method lookup is negligible and probably done only once, and there’s also JIT compiling that blurs things. And the implementation of get in LinkedList is intelligent enough to start from the end of the list when applicable. See the attached code, that’s worth what it’s worth, but the same amount of time is spent in both ways. Vincent -- Vincent Hennebert Anyware Technologies http://people.apache.org/~vhennebert http://www.anyware-tech.com Apache FOP Committer FOP Development/Consulting
import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class ListVsLinkedList { private static final int REPEAT_TEST = 1000; private static final int NB_ADDITIONS = 100000; /** * @param args */ public static void main(String[] args) { List<Integer> list = new LinkedList<Integer>(); LinkedList<Integer> linkedList = new LinkedList<Integer>(); List<Long> timeList = new ArrayList<Long>(REPEAT_TEST); List<Long> timeLinkedList = new ArrayList<Long>(REPEAT_TEST); for (int i = 0; i < 1000; i++) { long timeBefore = System.currentTimeMillis(); for (int j = 0; j < NB_ADDITIONS; j++) { list.add(j); list.get(list.size() - 1); } long timeAfter = System.currentTimeMillis(); timeList.add(timeAfter - timeBefore); list.clear(); timeBefore = System.currentTimeMillis(); for (int j = 0; j < NB_ADDITIONS; j++) { linkedList.add(j); linkedList.getLast(); } timeAfter = System.currentTimeMillis(); timeLinkedList.add(timeAfter - timeBefore); linkedList.clear(); } long sum = 0; for (long time: timeList) { sum += time; } System.out.println("List: " + (sum / REPEAT_TEST) + "ms"); sum = 0; for (long time: timeLinkedList) { sum += time; } System.out.println("LinkedList: " + (sum / REPEAT_TEST) + "ms"); } }