Running on Java 24-ea+21-2447 (Preview)
Home of The JavaSpecialists' Newsletter

090Autoboxing Ourselves in Java 5

Author: Dr. Heinz M. KabutzDate: 2004-06-22Java Version: 5Category: Performance
 

Abstract: We look at the new Java 5 features: Generics, autoboxing and the for-in statement. It should make our code more maintainable without sacrificing performance.

 

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 [ISBN 0932633420] : 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.

javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.

Autoboxing Ourselves in Java 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 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 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

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '23 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...