Tuesday, February 27, 2007

toString() and primitive values

How can one convert a primitive value such as integer or boolean to String object?

Well, there are many ways. There is one way that I have seen so many times:

String strValue = new Integer(intValue).toString();

or

String strValue = new Boolean(booleanValue).toString();

Similarly new instance can be created and the toString() method invoked on classes such as Integer, Long, Float, Double, Byte, Short and Boolean.

The problem is that a boxed primitive is allocated just to call toString() method on it. Each time this is executed, a new instance, new object is created. However, object creation is not necessary and can be avoided. Creating object just for one method call is highly inefficient as the object can be garbage collected on the consecutive line.

The solution

It is more efficient to use the static form of toString() method, which takes the primitive value as a parameter.

String strValue = Integer.toString(intValue);

or

String strValue = Boolean.toString(booleanValue);

Side note

...and please don't do the following

Integer number = ...
String strValue = Integer.toString(number.intValue());

If you already have an instance of integer wrapper class, simply call

String strValue = number.toString();

Thursday, February 22, 2007

Log4J Logger vs. Category

Logging is the practice of recording sequential data. This is also a low-tech method of debugging and in some cases also the only way as the proper debugging tools may not be always available or applicable. Logging in Java can range from simple System.out.println() statements to usage of sophisticated logging frameworks.

At the time of writing there are several logging frameworks for logging in Java available. There is a popular and probably the most widely used Log4J framework. Younger brother of Log4J is the Java's Logging API that became part of Java SE in version 1.4. See How does the Java logging API stack up against log4j for comparison. The are many other logging frameworks: SimpleLog, jLo, Protomatter Syslog, etc.

There are also several frameworks that enable abstraction from logging frameworks, also known as logging bridges (Apache Commons Logging, log-bridge). These allow switching between logging frameworks. These and many others can be found at Open Source Logging Tools in Java at java-source.net.

Log4J was one of the early logging frameworks that gained popularity and is present in many source code bases. In some cases you could encounter usage of Category class rather than Logger. If you work or worked on projects that are built on top of relatively young frameworks, you may not even know that Category class exists as its natural habitat is in old Java code. I hadn't known that Category class existed until I saw it one day. I saw it in a place where I would usually use Logger class. Since that day I kept reminding myself to look at it and see what's different from Logger class and why would one use it.

So what is the difference between Category and Logger classes? The Java documentation in Category class states

This class has been deprecated and replaced by the Logger subclass. It will be kept around to preserve backward compatibility until mid 2003.

Logger is a subclass of Category, i.e. it extends Category. In other words, a logger is a category. Thus, all operations that can be performed on a category can be performed on a logger. Internally, whenever log4j is asked to produce a Category object, it will instead produce a Logger object. Log4j 1.2 will never produce Category objects but only Logger instances. In order to preserve backward compatibility, methods that previously accepted category objects still continue to accept category objects.

Then the following example shows how Category was used and how Logger should be used.

// Deprecated form:
Category cat = Category.getInstance("foo.bar");

// Preferred form for retrieving loggers:
Logger logger = Logger.getLogger("foo.bar");

And that's it. That's all you have to do to replace Category with Logger (apart from renaming the variable).

The documentation also says

There is absolutely no need for new client code to use or refer to the Category class. Whenever possible, please avoid referring to it or using it.

Why is this important? The plan is that from Log4J version 1.3 Category class will be removed! What can we do to prepare our code for Log4J 1.3? Well Preparing for Log4J version 1.3 has it all spelled out. It's worth to read if you want to understand all implications this upgrade may have. I just shamelessly paste the steps here:

  1. Never refer to the Category class directly, refer to Logger instead.
  2. Do not invoke the deprecated Category.getRoot method. Invoke Logger.getRootLogger method instead.
  3. Do not invoke the deprecated Category.getInstance(String) method. Invoke Logger.getLogger(String) method instead.
  4. Do not invoke the deprecated Category.getInstance(Class) method. Invoke Logger.getLogger(Class) method instead.
  5. Never refer to the Priority class, refer to Level class instead.
  6. Do not invoke the deprecated Category.setPriority(Priority) method. Invoke Logger.setLevel(Level) method instead.
  7. Do not invoke the deprecated Priority.toPriority(int) method. Invoke Level.toLevel(int) method instead. The same holds true for the other variants of the Priority.toPriority method.
  8. Never refer to the deprecated Priority.FATAL, Priority.ERROR, Priority.WARN, Priority.INFO, Priority.DEBUG fields. Refer to the Level.FATAL, Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG fields instead.

  9. If you confiugure appenders programmatically, do not forget to invoke the activateOptions method of an appender after you have instantiated it and set its options.

and as the above mentioned document says

For 99.99% of users, this translates to the following string find-and-replace operations:
  1. Replace the string "Category.getInstance" with the string "Logger.getLogger".
  2. Replace the string "Category.getRoot" with the string "Logger.getRootLogger".
  3. Replace the string "Category" with the string "Logger".
  4. Replace the string "Priority" with the string "Level".

Happy logging!

Tuesday, February 06, 2007

To Vista or Not To Vista?

Sysadmin in our company posted a message regarding Vista installations. I found it very funny and quote him here with his permission:

On a related note now that Vista has been officially released, and inspired by some helpful pages that others have produced I thought I'd preempt the inevitable requests for installation and come up with the following decision-tree to see if you qualify for an upgrade:

Vista Installation Decision Tree

It's all crystal clear now :-)

Sunday, February 04, 2007

Trailing Comma in Arrays

Most of us know how to initialize arrays. A usual way to initialize array is to specify all its elements. For example an array of integers can be initialized in following way:

Integer[] integerArray = new Integer[] {
new Integer(1),
new Integer(2),
new Integer(4)
};

I was generating code for a unit test and needed to create a List that I would pass to the constructor of a particular class I wanted to test. So I took the easiest way to create array then convert it to the list. In the process I generated the elements of the array by copying and pasting previously added element. The code looked like this:

List initList = Arrays.asList(new Integer[] {
new Integer(1),
new Integer(2),
new Integer(1),
new Integer(2),
});

Notice the trailing comma! To my surprise, my IDE did not warn me about compilation error, moreover the code compiled and ran just fine.

According to Java Language Specification, chapter 10.6 Array Initializers

An array initializer is written as a comma-separated list of expressions, enclosed by braces "{" and "}".

The length of the constructed array will equal the number of expressions.

The expressions in an array initializer are executed from left to right in the textual order they occur in the source code. The nth variable initializer specifies the value of the n-1st array component. Each expression must be assignment-compatible (§5.2) with the array's component type, or a compile-time error results.

If the component type is itself an array type, then the expression specifying a component may itself be an array initializer; that is, array initializers may be nested.

A trailing comma may appear after the last expression in an array initializer and is ignored.

I must admit that I never used trailing commas in arrays in my whole software engineering career and on this occasion, this took my be surprise. I guess making mistakes it one way of discovering the truth and realizing that a mistake may not be a mistake after all.

So, there you go! Initializing arrays in Java with a trailing comma is totally valid. I learn something new every day :-)


Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.