Thursday, September 17, 2009

Watch your Java compiler

So, scenario #1 is like:


class A {
public static final String x = "foo";
public static String y = "bar";
}

class B {
public static void main(String[] args) {
System.out.println(A.x);
System.out.println(A.y);
}
}


You compile both classes and run B - you get an output as follows:
foo
bar

And then you change A thusly:


class A {
public static final String x = "baz";
public static String y = "qux";
}


and compile only A. Then run B. The output?
foo
qux

What just happened? The compiler is in-lining the static final x, but not y. Well, that comes from the Java language spec.

Scenario #2:


public abstract class A {
public A() {
System.out.println(bar().getClass());
}
public void foo() {
// do something
}
public abstract String bar();
}

public class B extends A {
final String value = getBar();
public String bar() {
return value;
}
private String getBar() {
return "barvalue";
}
public static void main(String[] args) {
System.out.println(new B().bar());
}
}

// invoke it
new B().foo();


Throws NullPointerException, but why? If you decompile B.class, you will find:


public class B extends A {
String value = null;
public B() {
super();
value = getBar();
}
public String bar() {
return value;
}
private String getBar() {
return "barvalue";
}
public static void main(String[] args) {
System.out.println(new B().bar());
}
}


So as it turns out, "final" variable is a compiler trick, as are keywords like "private" and "protected". You better be watching your Java compiler.

Wednesday, August 19, 2009

Almost literals - Initializing Java collections

Dynamic languages like Python and Ruby provide built-in syntax to express common data structures as literals. However, Java provides literal syntax only for arrays.

Although not pretty, here is how you can quickly initialize Java collections:


import java.util.*;

public class Literals {
private static class HashMapNow<K, V> extends HashMap<K, V> {
public HashMapNow<K, V> with(K key, V value) {
put(key, value);
return this;
}
}

public static void main(String[] args) {
// initialize a list
List<String> list = Arrays.asList("a", "b", "c", "c");

// initialize a set
Set<String> set = new HashSet<String>(Arrays.asList("a", "b", "c", "c"));

// initialize a map
Map<String, String> map = new HashMapNow<String, String>()
.with("a", "1")
.with("b", "2")
.with("c", "3")
.with("c", "4");

// print them all
System.out.println(list);
System.out.println(set);
System.out.println(map);
}
}


2009 Aug 25 [Update]: As suggested by Eric (in comments below), the initialization can be done in the static block - though it is admittedly quirkier. Cleaner options are available in Google Collections and LambdaJ.

Disqus for Char Sequence