Java Specialists' Java Training Europehome of the java specialists' newsletter

The Java Specialists' Newsletter
Issue 0902004-06-22 Category: Performance Java version: Sun JDK 1.5.0-beta2

GitHub Subscribe Free RSS Feed

Autoboxing Yourself in JDK 1.5

by Dr. Heinz M. Kabutz

Welcome to the 90th edition of The Java(tm) Specialists' Newsletter. I would like to thank all my loyal readers for spreading the word about this newsletter. Today is a special day for my son Maxi, as he celebrates his 6th birthday. Kids are a great way of reminding you how old you are getting... Before I know it, he'll be asking me to buy him a car...

The Psychology of Computer Programming: A great book by Gerald Weinberg (also wrote Secrets of Consulting, reviewed in TJSN 048) This is the type of book that you can pick up, read three pages, have a few laughs, and then put it down again.

In his book, Weinberg assumes that programmers are of above-average intelligence. The first edition of the book was written in the year I was born (1971). At the time of writing, before the invention of contact lenses, most programmers really did look like archetypal nerds. Popular thought was that you had to be good at Mathematics to become a programmer. Since it takes a bit of intelligence to be good at Maths (and a lot of hard work), the less-brainy kids stayed away from computer programming. My, how the industry has changed!

Today, I cringe when people ask me what I do for a living. My favourite answer is: "I stand in front of crowds and tell jokes." That sounds far more interesting than: "I go to corporations and teach their programmers how to be more effective in Java and Object Orientation." As soon as I mention that my job has anything to do with computers, the reply I get every time is: "Oh yes, my uncle/brother/sister/father/son/mother/auntie is an absolute genius with computers - he even did an MCS-whats-the-name."

This is a classic book that every programmer and project manager should read. You can probably pick up a dusty copy of the original 1971 print in your computer science department library.

NEW: Please see our new "Extreme Java" course, combining concurrency, a little bit of performance and Java 8. Extreme Java - Concurrency & Performance for Java 8.

Autoboxing Yourself in JDK 1.5

From the old (1971) to the new (2004).

On my last Java Course in Pretoria (South Africa), I demonstrated to my class how autoboxing worked. Our experiments showed that autoboxing can be inefficient. As nice as the feature is, it is also rather dangerous. Java learners could use autoboxing by mistake, negatively affecting performance.

However, before I delve into autoboxing, I would like to write something about the new for construct.

The New for Construct

About two-and-a-half years ago, I complained bitterly in TJSN 040 about the Iterator idiom. I felt that using a for or a while loop, together with a typecast, tended to make our code look ugly. The new for construct in JDK 1.5 finally addresses my complaint. This is how you can use it in your code:

import java.util.*;

public class NewFor {
  public static void main(String[] args) {
    // we can use type-safe collections...
    Collection<String> names = new ArrayList<String>();
    names.add("Maxi");
    names.add("Connie");
    names.add("Helene");
    names.add("Heinz");
    //names.add(new Integer(42)); -- does not compile!
    // look at the new for construct:
    for (String name : names) {
      System.out.println("name = " + name);
    }
  }
}
  

Endorsement: After having spent several years using different IDEs and editors (JBuilder, VI, Notepad, Eclipse), I have finally come to rest. Last year I took IntelliJ IDEA for a spin, and have not looked back since. It just always does exactly what I expect it to do. I can do almost anything with keystrokes, instead of moving my hands off the keyboard onto my mouse. In addition, it supports all of the JDK 1.5 features already, even though that version of the JDK is only in beta. Do yourself a favour, take the latest early access version for a test run: IntelliJ EAP. [No, I am not being paid for endorsing IntelliJ, and I understand completely if you prefer Eclipse.]

We can combine autoboxing with generics. (Autoboxing is the process of converting primitives to objects and vice-versa, automatically). My example code in newsletter # 40 could have been written more elegantly like so:

  public void showAging(Collection<Integer> ages) {
    for(int age : ages) {
      System.out.println("Now you're " + age +
        ", in 3 years time, you'll be " + (age + 3));
    }
  }
  

I discovered by accident that you can also use this new for construct with arrays:

public class NewForArrays {
  public static void main(String[] args) {
    String[] names = {"Maxi", "Connie", "Helene", "Heinz"};
    for (String name : names) {
      System.out.println("name = " + name);
    }
  }
}
  

Isn't that beautiful? At long last, a consistent way of iterating through collections and arrays. This even works for arrays of primitives:

public class NewForPrimitiveArrays {
  public static void main(String[] args) {
    int[] daysPerMonth = {31,28,31,30,31,30,31,31,30,31,30,31};
    int totalDays = 0;
    for (int days : daysPerMonth) {
      totalDays += days;
    }
    System.out.println("totalDays = " + totalDays);
  }
}
  

When we decompile the class, we see the following (not too unreasonable):

public class NewForPrimitiveArrays {
  public static void main(String args[]) {
    int daysPerMonth[] = {
      31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    };
    int totalDays = 0;
    int arr$[] = daysPerMonth;
    int len$ = arr$.length;
    for(int i$ = 0; i$ < len$; i$++) {
      int days = arr$[i$];
      totalDays += days;
    }
    System.out.println("totalDays = " + totalDays);
  }
}

A great fear of programmers is that you might use some new construct that then makes your code unacceptably slow. Here is some code that compares the performance of "old" and "new" for constructs:

import java.util.*;

public class NewForPerformance {
  public static void main(String[] args) {
    // let's look at the performance difference of for construct
    Collection<Integer> numbers = new ArrayList<Integer>(10000);
    for(int i=0;i<10000; i++) {
      // I can add an "int" to a collection of Integer, thanks
      // to the autoboxing construct shamelessly copied from C#
      numbers.add((int)Math.random());
    }
    oldFor(numbers);
    newFor(numbers);
  }
  private static void oldFor(final Collection<Integer> numbers) {
    measureIterations("oldFor", new Runnable() {
      public void run() {
        for(Iterator<Integer> it = numbers.iterator(); it.hasNext();) {
          Integer i = it.next();
        }
      }
    });
  }
  private static void newFor(final Collection<Integer> numbers) {
    measureIterations("newFor", new Runnable() {
      public void run() {
        for(Integer i : numbers);
      }
    });
  }
  private static void measureIterations(String method, Runnable r) {
    long start = System.currentTimeMillis();
    int iterations = 0;
    while(System.currentTimeMillis() - start <= 2000) {
      r.run();
      iterations++;
    }
    System.out.println(method + ": " + iterations + " in " +
        (System.currentTimeMillis()-start) + "ms");
  }
}

When I run this, I get the following output:

oldFor: 3532 in 2003ms
newFor: 3561 in 2003ms

The two methods are similar enough that we can declare that there is no difference between them. So, would you not rather use the new for construct instead of struggling with the old iterators?

Danger Lurking Below

Let us presume that armies of Java programmers will jump at the opportunity of using Generics and the new for construct. This will make arrays redundant, since autoboxing allows us to use ints with collections (note that we are adding and getting the values from the collection as the primitive data type int, but the type of object in the collection is Integer):

import java.util.*;

public class AutoBoxing {
  public static void main(String[] args) {
    Collection<Integer> values = new ArrayList<Integer>();
    for (int i=0; i<100; i++) {
      values.add(i);
    }
    for(int val : values) {
      System.out.println(val);
    }
  }
}
  

Let's see what happens when we have a collection of numbers, and we want to increment all the values:

import java.util.*;

public class AutoBoxingIncrement {
  public static void main(String[] args) {
    // we set up a Collection containing Integers and an int[]
    List<Integer> values = new ArrayList<Integer>();
    int[] valuesArray = new int[1000];
    for (int i = 0; i < 1000; i++) {
      values.add(i);
      valuesArray[i] = i;
    }

    // let's time how quickly we can increment the 1000 values
    long time = System.currentTimeMillis();
    // we must do it a few times to see the difference
    for (int j = 0; j < 100000; j++) {
      for (int i = 0; i < values.size(); i++) {
        values.set(i, values.get(i) + 1);
      }
    }
    System.out.println("autoboxing with generics took " +
        (System.currentTimeMillis() - time) + "ms");

    // now we try with an array
    time = System.currentTimeMillis();
    for (int j = 0; j < 100000; j++) {
      for (int i = 0; i < valuesArray.length; i++) {
        valuesArray[i]++;
      }
    }
    System.out.println("Using a plain array took " +
        (System.currentTimeMillis() - time) + "ms");
  }
}
  

When I run this on my little notebook, I see a huge difference in performance. The direct array method of using ints is about 20 times faster!!!

    autoboxing with generics took 9954ms
    Using a plain array took 551ms
  

Generics were extremely easy to learn, and after using them for a few hours, I did not want to go back to type-unsafe Collections. However, we have to be aware when we may be doing stupid things that could impact performance, such as autoboxing when we should not.

Kind regards

Heinz

Performance Articles Related Java Course

Extreme Java - Concurrency and Performance for Java 8
Extreme Java - Advanced Topics for Java 8
Design Patterns
In-House Courses

© 2010-2016 Heinz Kabutz - All Rights Reserved Sitemap
Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. JavaSpecialists.eu is not connected to Oracle, Inc. and is not sponsored by Oracle, Inc.