// collectionsindepth/ListPerformance.java // (c)2016 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://mindviewinc.com/Books/OnJava/ for more book information. // Demonstrates performance differences in Lists // Small to keep build testing short: // {Args: 100 500} import java.util.*; import onjava.*; public class ListPerformance { static SplittableRandom rand = new SplittableRandom(); static int reps = 1000; static List>> tests = new ArrayList<>(); static List>> qTests = new ArrayList<>(); static { tests.add(new Test>("add") { @Override int test(List list, TestParam tp) { int loops = tp.loops; int listSize = tp.size; for(int i = 0; i < loops; i++) { list.clear(); for(int j = 0; j < listSize; j++) list.add(j); } return loops * listSize; } }); tests.add(new Test>("get") { @Override int test(List list, TestParam tp) { int loops = tp.loops * reps; int listSize = list.size(); for(int i = 0; i < loops; i++) list.get(rand.nextInt(listSize)); return loops; } }); tests.add(new Test>("set") { @Override int test(List list, TestParam tp) { int loops = tp.loops * reps; int listSize = list.size(); for(int i = 0; i < loops; i++) list.set(rand.nextInt(listSize), 47); return loops; } }); tests.add(new Test>("iteradd") { @Override int test(List list, TestParam tp) { final int LOOPS = 1000000; int half = list.size() / 2; ListIterator it = list.listIterator(half); for(int i = 0; i < LOOPS; i++) it.add(47); return LOOPS; } }); tests.add(new Test>("insert") { @Override int test(List list, TestParam tp) { int loops = tp.loops; for(int i = 0; i < loops; i++) list.add(5, 47); // Minimize random-access cost return loops; } }); tests.add(new Test>("remove") { @Override int test(List list, TestParam tp) { int loops = tp.loops; int size = tp.size; for(int i = 0; i < loops; i++) { list.clear(); list.addAll(new CountingIntegerList(size)); while(list.size() > 5) list.remove(5); // Minimize random-access cost } return loops * size; } }); // Tests for queue behavior: qTests.add(new Test>("addFirst") { @Override int test(LinkedList list, TestParam tp) { int loops = tp.loops; int size = tp.size; for(int i = 0; i < loops; i++) { list.clear(); for(int j = 0; j < size; j++) list.addFirst(47); } return loops * size; } }); qTests.add(new Test>("addLast") { @Override int test(LinkedList list, TestParam tp) { int loops = tp.loops; int size = tp.size; for(int i = 0; i < loops; i++) { list.clear(); for(int j = 0; j < size; j++) list.addLast(47); } return loops * size; } }); qTests.add( new Test>("rmFirst") { @Override int test(LinkedList list, TestParam tp) { int loops = tp.loops; int size = tp.size; for(int i = 0; i < loops; i++) { list.clear(); list.addAll(new CountingIntegerList(size)); while(list.size() > 0) list.removeFirst(); } return loops * size; } }); qTests.add(new Test>("rmLast") { @Override int test(LinkedList list, TestParam tp) { int loops = tp.loops; int size = tp.size; for(int i = 0; i < loops; i++) { list.clear(); list.addAll(new CountingIntegerList(size)); while(list.size() > 0) list.removeLast(); } return loops * size; } }); } static class ListTester extends Tester> { public ListTester(List collection, List>> tests) { super(collection, tests); } // Fill to the appropriate size before each test: @Override protected List initialize(int size) { collection.clear(); collection.addAll(new CountingIntegerList(size)); return collection; } // Convenience method: public static void run(List list, List>> tests) { new ListTester(list, tests).timedTest(); } } public static void main(String[] args) { if(args.length > 0) Tester.defaultParams = TestParam.array(args); // Can only do these two tests on an array: Tester> arrayTest = new Tester>(null, tests.subList(1, 3)) { // This is called before each test. It // produces a non-resizeable array-backed list: @Override protected List initialize(int size) { Integer[] ia = new Integer[size]; Arrays.setAll(ia, new Count.Integer()::get); return Arrays.asList(ia); } }; arrayTest.setHeadline("Array as List"); arrayTest.timedTest(); Tester.defaultParams= TestParam.array( 10, 5000, 100, 5000, 1000, 1000, 10000, 200); if(args.length > 0) Tester.defaultParams = TestParam.array(args); ListTester.run(new ArrayList<>(), tests); ListTester.run(new LinkedList<>(), tests); ListTester.run(new Vector<>(), tests); Tester.fieldWidth = 12; Tester> qTest = new Tester>( new LinkedList<>(), qTests); qTest.setHeadline("Queue tests"); qTest.timedTest(); } } /* Output: --- Array as List --- size get set 100 19 20 --------------------- ArrayList --------------------- size add get set iteradd insert remove 100 31 19 21 33 158 114 --------------------- LinkedList --------------------- size add get set iteradd insert remove 100 30 44 45 77 143 56 ----------------------- Vector ----------------------- size add get set iteradd insert remove 100 26 32 33 64 147 67 -------------------- Queue tests -------------------- size addFirst addLast rmFirst rmLast 100 33 71 102 135 */