Hidden Features of Java

Thursday, 12. February 2009

A few days ago, I registered stackoverflow.com and found an interesting post: what are hidden features of Java?

The stuffs that I didn’t know before are

  • Double brace initialization
  • 
    	Map map=new HashMap<String,String>() {
    		{
    			put("key1","value1");
    			put("key2","value2");
    		}
    	};
    
  • Instance initializer
  • 
    public class Initializer {
    	static {
    		System.out.println("static");
    	}
    	{
    		System.out.println("instance");
    	}
    	public Initializer() {
    		System.out.println("constructor");
    	}
    }
    
  • Covariant return type
  • 
    	abstract class Base {
    		abstract List getList();
    	}
    
    	class Sub extends Base {
    		@Override
    		ArrayList getList() {
    			return null;
    		}
    	}
    

Double brace initialization uses instance initializer because first brace is for declairing annomymous inner class and second brace is for instance initializer block.

Java VM Optimization

Tuesday, 20. January 2009

I saw a presentation on Java VM optimization via InfoQ. Java is originally slow, but HotSpot compiler is getting smarter enough to free Java from the shame.

http://www.infoq.com/presentations/pampuch-vm-optimizations-language-designers

Java deadlock detection

Friday, 8. August 2008

Detecting deadlock is one of common features of Java profiling tools but I haven’t experienced the situation where those tools detect deadlock from code I wrote. In fact, deadlock is hazardous because it is difficult to predict and reproduce.

I wondered under what conditions do profilers detect deadlock and then report it, so I wrote code that reaches deadlock.


package com.grayger.deadlock;

public class SimpleDeadlocker {
	private final static Object OBJ1=new Object();
	private final static Object OBJ2=new Object();

	private final static int LOOP=100;

	public void obj1First() {
		synchronized(OBJ1) {
			printInfo("Hold OBJ1");
			synchronized(OBJ2) {
				printInfo("Hole OBJ2");
			}
			printInfo("Release OBJ2");
		}
		printInfo("Release OBJ1");
	}

	public void obj2First() {
		synchronized(OBJ2) {
			printInfo("Hold OBJ2");
			synchronized(OBJ1) {
				printInfo("Hole OBJ1");
			}
			printInfo("Release OBJ1");
		}
		printInfo("Release OBJ2");
	}

	private void printInfo(String info) {
		System.out.println(Thread.currentThread().getName()+" "+info);
	}

	public static void main(String args[]) {
		final SimpleDeadlocker d=new SimpleDeadlocker();
		Thread t1=new Thread(new Runnable() {
			public void run() {
				for(int i=0;i<loop;i++)>
					d.obj1First();
				}
				d.printInfo("Terminated");
			}
		}, "OBJ1_First");

		Thread t2=new Thread(new Runnable() {
			public void run() {
				for(int i=0;i<loop;i++)>
					d.obj2First();
				}
				d.printInfo("Terminated");
			}
		}, "OBJ2_First");

		t1.start();
		t2.start();
	}
}

Above example can be refactored as follows:


package com.grayger.deadlock;

public class Deadlocker {
	private final static int LOOP=100;

	static class Deadlock1 {
		private final static Object OBJ1=new Object();
		private final static Object OBJ2=new Object();		

		public void obj1First() {
			synchronized(OBJ1) {
				printInfo("Hold OBJ1");
				synchronized(OBJ2) {
					printInfo("Hole OBJ2");
				}
				printInfo("Release OBJ2");
			}
			printInfo("Release OBJ1");
		}
	}

	static class Deadlock2 {
		private final static Object OBJ1=new Object();
		private final static Object OBJ2=new Object();

		public void obj2First() {
			synchronized(OBJ2) {
				printInfo("Hold OBJ2");
				synchronized(OBJ1) {
					printInfo("Hole OBJ1");
				}
				printInfo("Release OBJ1");
			}
			printInfo("Release OBJ2");
		}
	}

	public static void printInfo(String info) {
		System.out.println(Thread.currentThread().getName()+" "+info);
	}

	public static void main(String args[]) {
		final Deadlock1 d1=new Deadlock1();
		final Deadlock2 d2=new Deadlock2();
		Thread t1=new Thread(new Runnable() {
			public void run() {
				for(int i=0;i<loop;i++)>
					d1.obj1First();
				}
				Deadlocker.printInfo("Terminated");
			}
		}, "OBJ1_First");

		Thread t2=new Thread(new Runnable() {
			public void run() {
				for(int i=0;i<loop;i++)>
					d2.obj2First();
				}
				Deadlocker.printInfo("Terminated");
			}
		}, "OBJ2_First");

		t1.start();
		t2.start();
	}
}

@Override annotation in Java6

Friday, 8. August 2008

The @Override annotation added in Java5 is very useful. Recently I found out the annotation of Java6 differs from that of Java5. Java6 allows annotating a method that implements a method declared in interface with @Override whereas Java5 doesn’t allow it.

Unfortunately I couldn’t find any document on the change from java.sun.com site. Missing this issue from the release note of Java6 seems to be a mistake as http://blogs.sun.com/ahe/entry/override_snafu says.