Showing posts with label java7. Show all posts
Showing posts with label java7. Show all posts

Saturday, June 29, 2013

Java 7 Swing: Creating Translucent and Shaped Windows

Java 7 Swing supports windows with transparency and non-rectangular shapes.

The following screenshot shows a circular window created with 75% opacity.

You can create a translucent window by altering its opacity using the setOpacity method on a JFrame. Note that you can only create translucent windows if the underlying operating system supports them. Also, ensure that the window is undecorated by calling setUndecorated(true).

To change the shape of the window, call the setShape method inside the componentResized method, so that if the window is resized, the shape is recalculated as well.

Sample code to create a translucent, circular window is shown below:

import java.awt.Color;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.Ellipse2D;

import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class TranslucentCircularFrame extends JFrame {

  /**
   * Creates a frame containing a text area and a button. The frame has a
   * circular shape and a 75% opacity.
   */
  public TranslucentCircularFrame() {
    super("Translucent Circular Frame");
    setLayout(new GridBagLayout());
    final JTextArea textArea = new JTextArea(3, 50);
    textArea.setBackground(Color.GREEN);
    add(textArea);
    setUndecorated(true);

    // set the window's shape in the componentResized method, so
    // that if the window is resized, the shape will be recalculated
    addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        setShape(new Ellipse2D.Double(0, 0, getWidth(), getHeight()));
      }
    });

    // make the window translucent
    setOpacity(0.75f);

    setLocationRelativeTo(null);
    setSize(250, 250);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
  }

  public static void main(String[] args) {

    // Create the GUI on the event-dispatching thread
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        GraphicsEnvironment ge = GraphicsEnvironment
            .getLocalGraphicsEnvironment();

        // check if the OS supports translucency
        if (ge.getDefaultScreenDevice().isWindowTranslucencySupported(
            GraphicsDevice.WindowTranslucency.TRANSLUCENT)) {
          new TranslucentCircularFrame();
        }
      }
    });
  }
}

Wednesday, August 15, 2012

Java 7: Fork/Join Framework Example

The Fork/Join Framework in Java 7 is designed for work that can be broken down into smaller tasks and the results of those tasks combined to produce the final result.

In general, classes that use the Fork/Join Framework follow the following simple algorithm:

// pseudocode
Result solve(Problem problem) {
  if (problem.size < SEQUENTIAL_THRESHOLD)
    return solveSequentially(problem);
  else {
    Result left, right;
    INVOKE-IN-PARALLEL {
      left = solve(extractLeftHalf(problem));
      right = solve(extractRightHalf(problem));
    }
    return combine(left, right);
  }
}
In order to demonstrate this, I have created an example to find the maximum number from a large array using fork/join:
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

public class MaximumFinder extends RecursiveTask<Integer> {

  private static final int SEQUENTIAL_THRESHOLD = 5;

  private final int[] data;
  private final int start;
  private final int end;

  public MaximumFinder(int[] data, int start, int end) {
    this.data = data;
    this.start = start;
    this.end = end;
  }

  public MaximumFinder(int[] data) {
    this(data, 0, data.length);
  }

  @Override
  protected Integer compute() {
    final int length = end - start;
    if (length < SEQUENTIAL_THRESHOLD) {
      return computeDirectly();
    }
    final int split = length / 2;
    final MaximumFinder left = new MaximumFinder(data, start, start + split);
    left.fork();
    final MaximumFinder right = new MaximumFinder(data, start + split, end);
    return Math.max(right.compute(), left.join());
  }

  private Integer computeDirectly() {
    System.out.println(Thread.currentThread() + " computing: " + start
                       + " to " + end);
    int max = Integer.MIN_VALUE;
    for (int i = start; i < end; i++) {
      if (data[i] > max) {
        max = data[i];
      }
    }
    return max;
  }

  public static void main(String[] args) {
    // create a random data set
    final int[] data = new int[1000];
    final Random random = new Random();
    for (int i = 0; i < data.length; i++) {
      data[i] = random.nextInt(100);
    }

    // submit the task to the pool
    final ForkJoinPool pool = new ForkJoinPool(4);
    final MaximumFinder finder = new MaximumFinder(data);
    System.out.println(pool.invoke(finder));
  }
}
The MaximumFinder class is a RecursiveTask which is responsible for finding the maximum number from an array. If the size of the array is less than a threshold (5) then find the maximum directly, by iterating over the array. Otherwise, split the array into two halves, recurse on each half and wait for them to complete (join). Once we have the result of each half, we can find the maximum of the two and return it.

Sunday, August 21, 2011

Java 7: ThreadLocalRandom for Concurrent Random Numbers

The ThreadLocalRandom class in JDK 7, allows you to generate random numbers from multiple threads. It is more efficient than using shared Random objects and will result in better performance as there is less overhead and contention.

In addition, this class also provides "bounded" generation methods.

For example, the statement below generates a random number between 1 (inclusive) and 100 (exclusive).

int random = ThreadLocalRandom.current().nextInt(1,100);
Wait, there's a BUG!
While trying out this class, I noticed that the SAME random numbers were being produced across all my threads. I then discovered this bug which reported the same issue I was having. It appears that the seed is never initialised so the same random numbers are produced every time. I wouldn't recommend using this class until the bug is fixed. The following code illustrates the issue:
//3 threads
for(int i = 0; i < 3; i++) {
    final Thread thread = new Thread() {
        @Override
        public void run() {
            System.out.print(Thread.currentThread().getName() + ":");

            //each thread prints 3 random numbers
            for(int j = 0; j < 3; j++) {
                final int random = ThreadLocalRandom.current().nextInt(1, 50);
                System.out.print(random + ",");
            }
            System.out.println();
        }
    };
    thread.start();
    thread.join();
}
prints:
Thread-0:1,5,24,
Thread-1:1,5,24,
Thread-2:1,5,24,

Sunday, August 14, 2011

Useful Eclipse Templates for Faster Coding

I wrote about my Eclipse code templates a few years ago and since then I've made a quite a few changes to them. I've added a few new templates to help with JUnit tests and xml parsing. I've also updated my existing file IO templates to use Java 7 features.

Templates are simply "magic words" or shortcuts to standard blocks of code or text. They are very handy because once you have them setup you don't have to waste time writing boilerplate code any more! An example of a pre-defined template in Eclipse is sysout which expands to System.out.println();. All you have to do is type sysout followed by Ctrl+Space to insert the statement into your Java source file.

To see what templates are defined in Eclipse:

  • Open your Preferences dialog by going to Windows > Preferences
  • On the navigation tree on the left, go to Java > Editor > Templates
  • You will see a list of pre-defined templates
  • You can add new ones by pressing the "New..." button
My templates are shown below. They can also be downloaded from my GitHub repository and then imported into Eclipse.

General Utility Templates:

Nameif
ContextJava statements
Descriptionif null
Pattern
if (${var} == null){
    ${cursor}
}
Nameif
ContextJava statements
Descriptionif not null
Pattern
if (${var} != null){
    ${cursor}
}
Namefor
ContextJava statements
Descriptioniterate over map
Pattern
${:import(java.util.Map.Entry)}
for(Entry<${key:argType(map,0)},${value:argType(map,1)}> entry :
                    ${map:var(java.util.Map)}.entrySet()) {
    ${key} key = entry.getKey();
    ${value} value = entry.getValue();
    ${cursor}
}
Namestrf
ContextJava
Descriptionformat string
Pattern
String.format("${word_selection}${}",${var}${cursor})
Namesysf
ContextJava statements
Descriptionprint formatted string to standard out
Pattern
System.out.printf("${word_selection}${}",${var}${cursor});
Namestatic_final
ContextJava type members
Descriptionstatic final field
Pattern
${visibility:link(
              public,
              protected,
              private)} static final ${type} ${NAME} = ${word_selection}${};

File IO Templates:
The following templates are useful for reading or writing files. They use Java 7 features such as try-with-resources to automatically close files. They also use methods from NIO2.0 to obtain a buffered reader and read the file.

Namereadfile
ContextJava statements
Descriptionread text from file
Pattern
${:import(java.nio.file.Files,
          java.nio.file.Paths,
          java.nio.charset.Charset,
          java.io.IOException,
          java.io.BufferedReader)}
try (BufferedReader in = Files.newBufferedReader(Paths.get(${fileName:var(String)}),
                                                 Charset.forName("UTF-8"))) {
    String line = null;
    while ((line = in.readLine()) != null) {
        ${cursor}
    }
} catch (IOException e) {
    // ${todo}: handle exception
}
Namereadfile
ContextJava statements
Descriptionread all lines from file as a list
Pattern
${:import(java.nio.file.Files,
          java.nio.file.Paths,
          java.nio.charset.Charset,
          java.util.List,
          java.util.ArrayList)}
Lis<String> lines = new ArrayList<>();
try{
	lines = Files.readAllLines(Paths.get(${fileName:var(String)}),
                                        Charset.forName("UTF-8"));
}catch (IOException e) {
    // ${todo}: handle exception
}
${cursor}
Namewritefile
ContextJava statements
Descriptionwrite text to file
Pattern
${:import(java.nio.file.Files,
          java.nio.file.Paths,
          java.nio.Charset,
          java.io.IOException,
          java.io.BufferedWriter)}
try (BufferedWriter out = Files.newBufferedWriter(Paths.get(${fileName:var(String)}),
                                                  Charset.forName("UTF-8"))) {
    out.write(${string:var(String)});
    out.newLine();
    ${cursor}
} catch (IOException e) {
    // ${todo}: handle exception
}

XML Templates:
The following templates are used to read xml files or strings and return a DOM.

Nameparsexml
ContextJava statements
Descriptionparse xml file as Document
Pattern
${:import(org.w3c.dom.Document,
          javax.xml.parsers.DocumentBuilderFactory,
          java.io.File,
          java.io.IOException,
          javax.xml.parsers.ParserConfigurationException,
          org.xml.sax.SAXException)}
Document doc = null;
try {
	doc = DocumentBuilderFactory.newInstance()
			.newDocumentBuilder()
			.parse(new File(${filename:var(String)}));
} catch (SAXException | IOException | ParserConfigurationException e) {
	// ${todo}: handle exception
}
${cursor}
Nameparsexml
ContextJava statements
Descriptionparse xml string as Document
Pattern
${:import(org.w3c.dom.Document,
          javax.xml.parsers.DocumentBuilderFactory,
          org.xml.sax.InputSource,
          java.io.StringReader,
          java.io.IOException,
          javax.xml.parsers.ParserConfigurationException,
          org.xml.sax.SAXException)}
Document doc = null;
try {
	doc = DocumentBuilderFactory.newInstance()
			.newDocumentBuilder()
			.parse(new InputSource(new StringReader(${str:var(String)})));
} catch (SAXException | IOException | ParserConfigurationException e) {
	// ${todo}: handle exception
}
${cursor}

Logging Templates:
The templates below are useful for creating a logger and logging messages. I use SLF4J, but they could easily be tweaked to use any other logging framework.

Namelogger
ContextJava type members
Descriptioncreate new logger
Pattern

${:import(org.slf4j.Logger,
          org.slf4j.LoggerFactory)}
private static final Logger LOGGER =
       LoggerFactory.getLogger(${enclosing_type}.class);
Namelogd
ContextJava statements
Descriptionlogger debug
Pattern
if(LOGGER.isDebugEnabled())
     LOGGER.debug(${word_selection}${});
${cursor}
Namelogi
ContextJava statements
Descriptionlogger info
Pattern
LOGGER.info(${word_selection}${});
${cursor}
Namelogerr
ContextJava statements
Descriptionlogger error
Pattern
LOGGER.error(${word_selection}${}, ${exception_variable_name});
Namelogthrow
ContextJava statements
Descriptionlog error and throw exception
Pattern
LOGGER.error(${word_selection}${}, ${exception_variable_name});
throw ${exception_variable_name};
${cursor}

JUnit Templates:
The templates below assist in writing JUnit tests.

Namebefore
ContextJava type members
Descriptionjunit before method
Pattern
${:import (org.junit.Before)}

@Before
public void setUp() {
    ${cursor}
}
Nameafter
ContextJava type members
Descriptionjunit after method
Pattern
${:import (org.junit.After)}

@After
public void tearDown() {
    ${cursor}
}
Namebeforeclass
ContextJava type members
Descriptionjunit beforeclass method
Pattern
${:import (org.junit.BeforeClass)}

@BeforeClass
public static void oneTimeSetUp() {
    // one-time initialization code
    ${cursor}
}
Nameafterclass
ContextJava type members
Descriptionjunit afterclass method
Pattern
${:import (org.junit.AfterClass)}

@AfterClass
public static void oneTimeTearDown() {
    // one-time cleanup code
    ${cursor}
}

Do YOU have any useful templates? If so, share them in the comments section!

Sunday, August 07, 2011

Java 7: WatchService for File Change Notification

The Watch Service API in JDK7 allows you to watch a directory for changes to files and receive notification events when a file is added, deleted or modified. You no longer need to poll the file system for changes which is inefficient and doesn't scale well.

The code below shows how you would use the Watch Service API. First, you have to create a WatchService for the file system and then register the directory you want to monitor with it. You have to specify which events (create, modify or delete) you are interested in receiving. Then start an infinite loop to wait for events. When an event occurs, a WatchKey is placed into the watch service's queue and you have to call take to retrieve it. You can then query the key for events and print them out.

/**
 * Watch the specified directory
 * @param dirname the directory to watch
 * @throws IOException
 * @throws InterruptedException
 */
public static void watchDir(String dir)
    throws IOException, InterruptedException{

  //create the watchService
  final WatchService watchService = FileSystems.getDefault().newWatchService();

  //register the directory with the watchService
  //for create, modify and delete events
  final Path path = Paths.get(dir);
  path.register(watchService,
            StandardWatchEventKinds.ENTRY_CREATE,
            StandardWatchEventKinds.ENTRY_MODIFY,
            StandardWatchEventKinds.ENTRY_DELETE);

  //start an infinite loop
  while(true){

    //remove the next watch key
    final WatchKey key = watchService.take();

    //get list of events for the watch key
    for (WatchEvent<?> watchEvent : key.pollEvents()) {

      //get the filename for the event
      final WatchEvent<Path> ev = (WatchEvent<Path>)watchEvent;
      final Path filename = ev.context();

      //get the kind of event (create, modify, delete)
      final Kind<?> kind = watchEvent.kind();

      //print it out
      System.out.println(kind + ": " + filename);
    }

    //reset the key
    boolean valid = key.reset();

    //exit loop if the key is not valid
    //e.g. if the directory was deleted
      if (!valid) {
          break;
      }
  }
}
Demo:
$ java Watcher &
$ touch foo
ENTRY_CREATE: foo
$ echo hello >> foo
ENTRY_MODIFY: foo
$ rm foo
ENTRY_DELETE: foo

Java 7: Working with Zip Files

The Zip File System Provider in JDK7 allows you to treat a zip or jar file as a file system, which means that you can perform operations, such as moving, copying, deleting, renaming etc, just as you would with ordinary files. In previous versions of Java, you would have to use ZipEntry objects and read/write using ZipInputStreams and ZipOutputStreams which was quite messy and verbose. The zip file system makes working with zip files much easier!

This post shows you how to create a zip file and extract/list its contents, all using a zip file system.

Constructing a zip file system:
In order to work with a zip file, you have to construct a "zip file system" first. The method below shows how this is done. You need to pass in a properties map with create=true if you want the file system to create the zip file if it doesn't exist.

/**
 * Returns a zip file system
 * @param zipFilename to construct the file system from
 * @param create true if the zip file should be created
 * @return a zip file system
 * @throws IOException
 */
private static FileSystem createZipFileSystem(String zipFilename,
                                              boolean create)
                                              throws IOException {
  // convert the filename to a URI
  final Path path = Paths.get(zipFilename);
  final URI uri = URI.create("jar:file:" + path.toUri().getPath());

  final Map<String, String> env = new HashMap<>();
  if (create) {
    env.put("create", "true");
  }
  return FileSystems.newFileSystem(uri, env);
}
Once you have a zip file system, you can invoke methods of the java.nio.file.FileSystem, java.nio.file.Path and java.nio.file.Files classes to manipulate the zip file.

Unzipping a Zip File:
In order to extract a zip file, you can walk the zip file tree from the root and copy files to the destination directory. Since you are dealing with a zip file system, extracting a directory is exactly the same as copying a directory recursively to another directory. The code below demonstrates this. (Note the use of the try-with-resources statement to close the zip file system automatically when done.)

/**
 * Unzips the specified zip file to the specified destination directory.
 * Replaces any files in the destination, if they already exist.
 * @param zipFilename the name of the zip file to extract
 * @param destFilename the directory to unzip to
 * @throws IOException
 */
public static void unzip(String zipFilename, String destDirname)
    throws IOException{

  final Path destDir = Paths.get(destDirname);
  //if the destination doesn't exist, create it
  if(Files.notExists(destDir)){
    System.out.println(destDir + " does not exist. Creating...");
    Files.createDirectories(destDir);
  }

  try (FileSystem zipFileSystem = createZipFileSystem(zipFilename, false)){
    final Path root = zipFileSystem.getPath("/");

    //walk the zip file tree and copy files to the destination
    Files.walkFileTree(root, new SimpleFileVisitor<Path>(){
      @Override
      public FileVisitResult visitFile(Path file,
          BasicFileAttributes attrs) throws IOException {
        final Path destFile = Paths.get(destDir.toString(),
                                        file.toString());
        System.out.printf("Extracting file %s to %s\n", file, destFile);
        Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
        return FileVisitResult.CONTINUE;
      }

      @Override
      public FileVisitResult preVisitDirectory(Path dir,
          BasicFileAttributes attrs) throws IOException {
        final Path dirToCreate = Paths.get(destDir.toString(),
                                           dir.toString());
        if(Files.notExists(dirToCreate)){
          System.out.printf("Creating directory %s\n", dirToCreate);
          Files.createDirectory(dirToCreate);
        }
        return FileVisitResult.CONTINUE;
      }
    });
  }
}
Creating a Zip File:
The following method shows how to create a zip file from a list of files. If a directory is passed in, it walks the directory tree and copies files into the zip file system:
/**
 * Creates/updates a zip file.
 * @param zipFilename the name of the zip to create
 * @param filenames list of filename to add to the zip
 * @throws IOException
 */
public static void create(String zipFilename, String... filenames)
    throws IOException {

  try (FileSystem zipFileSystem = createZipFileSystem(zipFilename, true)) {
    final Path root = zipFileSystem.getPath("/");

    //iterate over the files we need to add
    for (String filename : filenames) {
      final Path src = Paths.get(filename);

      //add a file to the zip file system
      if(!Files.isDirectory(src)){
        final Path dest = zipFileSystem.getPath(root.toString(),
                                                src.toString());
        final Path parent = dest.getParent();
        if(Files.notExists(parent)){
          System.out.printf("Creating directory %s\n", parent);
          Files.createDirectories(parent);
        }
        Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING);
      }
      else{
        //for directories, walk the file tree
        Files.walkFileTree(src, new SimpleFileVisitor<Path>(){
          @Override
          public FileVisitResult visitFile(Path file,
              BasicFileAttributes attrs) throws IOException {
            final Path dest = zipFileSystem.getPath(root.toString(),
                                                    file.toString());
            Files.copy(file, dest, StandardCopyOption.REPLACE_EXISTING);
            return FileVisitResult.CONTINUE;
          }

          @Override
          public FileVisitResult preVisitDirectory(Path dir,
              BasicFileAttributes attrs) throws IOException {
            final Path dirToCreate = zipFileSystem.getPath(root.toString(),
                                                           dir.toString());
            if(Files.notExists(dirToCreate)){
              System.out.printf("Creating directory %s\n", dirToCreate);
              Files.createDirectories(dirToCreate);
            }
            return FileVisitResult.CONTINUE;
          }
        });
      }
    }
  }
}
Listing the contents of a zip file:
This is the same as extracting a zip file except that instead of copying the files visited, we simply print them out:
/**
 * List the contents of the specified zip file
 * @param filename
 * @throws IOException
 * @throws URISyntaxException
 */
public static void list(String zipFilename) throws IOException{

  System.out.printf("Listing Archive:  %s\n",zipFilename);

  //create the file system
  try (FileSystem zipFileSystem = createZipFileSystem(zipFilename, false)) {

    final Path root = zipFileSystem.getPath("/");

    //walk the file tree and print out the directory and filenames
    Files.walkFileTree(root, new SimpleFileVisitor<Path>(){
      @Override
      public FileVisitResult visitFile(Path file,
          BasicFileAttributes attrs) throws IOException {
        print(file);
        return FileVisitResult.CONTINUE;
      }

      @Override
      public FileVisitResult preVisitDirectory(Path dir,
          BasicFileAttributes attrs) throws IOException {
        print(dir);
        return FileVisitResult.CONTINUE;
      }

      /**
       * prints out details about the specified path
       * such as size and modification time
       * @param file
       * @throws IOException
       */
      private void print(Path file) throws IOException{
        final DateFormat df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss");
        final String modTime= df.format(new Date(
                             Files.getLastModifiedTime(file).toMillis()));
        System.out.printf("%d  %s  %s\n",
                          Files.size(file),
                          modTime,
                          file);
      }
    });
  }
}
Further Reading:
Zip File System Provider

Tuesday, August 02, 2011

Java 7: Deleting a Directory by Walking the File Tree

The Java 7 NIO library allows you to walk a file tree and visit each file in the tree. You do this by implementing a FileVisitor and then calling Files.walkFileTree using the visitor. The visitor has four methods:
  • visitFile: Invoked for a file in a directory.
  • visitFileFailed: Invoked for a file that could not be visited.
  • preVisitDirectory: Invoked for a directory before entries in the directory are visited.
  • postVisitDirectory: Invoked for a directory after entries in the directory, and all of their descendants, have been visited.

Recursively Delete all Files in a Directory:
The following code shows how you can recursively delete a directory by walking the file tree. It does not follow symbolic links. I have overridden the visitFile and postVisitDirectory methods in SimpleFileVisitor so that when a file is visited, it is deleted and after all the files in the directory have been visited, the directory is deleted.

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import static java.nio.file.FileVisitResult.*;

Path dir = Paths.get("/tmp/foo");
try {
  Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {

      @Override
      public FileVisitResult visitFile(Path file,
              BasicFileAttributes attrs) throws IOException {

          System.out.println("Deleting file: " + file);
          Files.delete(file);
          return CONTINUE;
      }

      @Override
      public FileVisitResult postVisitDirectory(Path dir,
              IOException exc) throws IOException {

          System.out.println("Deleting dir: " + dir);
          if (exc == null) {
              Files.delete(dir);
              return CONTINUE;
          } else {
              throw exc;
          }
      }

  });
} catch (IOException e) {
  e.printStackTrace();
}

Sunday, July 31, 2011

Java 7: Try-With-Resources

The "Try With Resources", also called "Automatic Resource Management" (ARM), statement allows you to declare one or more resources in the try statement. When the statement completes, either successfully or unsuccessfully, all of its resources are closed automatically. You don't need to manually close resources in a finally block anymore, which means you don't have to worry about resource leaks.

Here is a method to make a copy of a file, using the Try-With-Resources statement. There are two resources defined in the try statement, which are automatically closed when the statement completes.

public static void copyFile(String src, String dest) throws IOException  {
  try (BufferedReader in = new BufferedReader(new FileReader(src));
       BufferedWriter out = new BufferedWriter(new FileWriter(dest))){
      String line;
      while((line = in.readLine()) != null) {
          out.write(line);
          out.write('\n');
      }
  }//no need to close resources in a "finally"
}
Here is another example, in which I have created my own resources implementing the AutoCloseable interface:
class ResourceA implements AutoCloseable{
  public void read() throws Exception{
    throw new Exception("ResourceA read exception");
  }
  @Override
  public void close() throws Exception {
    throw new Exception("ResourceA close exception");
  }
}

class ResourceB implements AutoCloseable{
  public void read() throws Exception{
    throw new Exception("ResourceB read exception");
  }
  @Override
  public void close() throws Exception {
    throw new Exception("ResourceB close exception");
  }
}

//a test method
public static void test() throws Exception{
  try (ResourceA a = new ResourceA();
       ResourceB b = new ResourceB()) {
    a.read();
    b.read();
  } catch (Exception e) {
    throw e;
  }
}
When this code is executed, a.read() throws an exception. The two resources are automatically closed, first B and then A (in the reverse order to which they were created). The "read" exception is thrown out of the method, and the two "close" exceptions are "suppressed". You can retrieve these suppressed exceptions by calling the Throwable.getSuppressed method from the exception thrown by the try block. The complete stack trace is shown below:
java.lang.Exception: ResourceA read exception
  at ResourceA.read(Dummy.java:48)
  at Dummy.test(Dummy.java:18)
  at Dummy.main(Dummy.java:38)
  Suppressed: java.lang.Exception: ResourceB close exception
    at ResourceB.close(Dummy.java:63)
    at Dummy.test(Dummy.java:20)
    ... 1 more
  Suppressed: java.lang.Exception: ResourceA close exception
    at ResourceA.close(Dummy.java:52)
    at Dummy.test(Dummy.java:20)
    ... 1 more
Further Reading:
The try-with-resources Statement

Java 7: Precise Rethrow

Previously, rethrowing an exception was treated as throwing the type of the catch parameter. For example, let's say that your try block could throw a ParseException or an IOException. To intercept all exceptions and rethrow them, you would have to catch Exception and declare your method as throwing an Exception. This is "imprecise rethrow", because you are throwing a general Exception type (instead of specific ones) and statements calling your method need to catch this general Exception.

This is illustrated below:

//imprecise rethrow.
//must use "throws Exception"
public static void imprecise() throws Exception{
	try {
		new SimpleDateFormat("yyyyMMdd").parse("foo");
		new FileReader("file.txt").read();
	} catch (Exception e) {
		System.out.println("Caught exception: " + e.getMessage());
		throw e;
	}
}
However, in Java 7, you can be more precise about the exception types being rethrown from a method. If you rethrow an exception from a catch block, you are actually throwing an exception type which:
  • the try block can throw,
  • no previous catch clause handles, and
  • is a subtype of one of the types in the declaration of the catch parameter
This leads to improved checking for rethrown exceptions. You can be more precise about the exceptions being thrown from the method and you can handle them a lot better at the calling site.
//java 7: precise rethrow.
//no longer "throws Exception"
public static void precise() throws ParseException, IOException{
	try {
		new SimpleDateFormat("yyyyMMdd").parse("foo");
		new FileReader("file.txt").read();
	} catch (Exception e) {
		System.out.println("Caught exception: " + e.getMessage());
		throw e;
	}
}

//this example handles ParseException
public static void precise2() throws IOException{
	try {
		new SimpleDateFormat("yyyyMMdd").parse("foo");
		new FileReader("file.txt").read();
	} catch(ParseException e){
	    System.out.println("Parse Exception");
	}catch (Exception e) {
		System.out.println("Caught exception: " + e.getMessage());
		throw e;
	}
}
(Note: Early documentation of this feature, states that you have to use a final modifier on the catch parameter, but this restriction was lifted later on, so is not necessary.)

Further Reading
Rethrowing Exceptions with More Inclusive Type Checking

Saturday, July 30, 2011

Java 7: Safe Varargs Method Invocation

In previous versions of Java, when you invoke a varargs method with a non-reifiable varargs type, the compiler generates a warning on the calling statement. Consider the code:
//varargs method
public static <T> void print(T... a) {
  for (T t : a) {
      System.out.println(t);
  }
}

//calling method
public static void main(String[] args){

  print("Hello", "World"); //this is fine

  print(new Pair<Integer,String>(1,"One"), new Pair<Integer,String>(2,"Two"));
  //WARNING: Type safety : A generic array of Pair<Integer,String>
  //is created for a varargs parameter
}
This because the compiler tries to create an array of Pair<Integer,String>[] to hold the varargs, which is not permitted because Pair<Integer,String> is type erased at runtime to just Pair. (More information here.) To suppress this warning, you need to add @SuppressWarnings("unchecked") to each method which makes a call to the varargs method.

In JDK7, the warning has been moved from the call site to the varargs method declaration and you can annotate the varargs method with @SafeVarargs in order to suppress it. This reduces the total number of warnings reported and those that have to be suppressed.

@SafeVarargs
// WARNING SUPPRESSED: Type safety: Potential heap pollution via varargs parameter a
public static <T> void print(T... a) {
  for (T t : a) {
      System.out.println(t);
  }
}

public static void main(String[] args){
  print("Hello", "World");
  print(new Pair<Integer,String>(1,"One"), new Pair<Integer,String>(2,"Two"));
  //no warnings :)
}
You can see this annotation used in JDK7's Arrays.asList method:

@SafeVarargs
public static <T> List<T> asList(T... a) {
   return new ArrayList<>(a);
}
Eclipse support:
Quick fix gives you the option to Add @SafeVarargs to your method.

Further Reading:
Improved Compiler Warnings and Errors When Using Non-Reifiable Formal Parameters with Varargs Methods

Java 7: Strings in Switch

Strings in switch gives you the ability to switch on string values just like you can currently do on primitives. Previously, you would have had to create chained if-else tests for string equality or introduce an enum, which is not necessary anymore.

The strings-in-switch feature works by first switching on the hashCode of the String and then performing an equals test.

Here is an example of a method which returns the number of days in a month. It uses if-else statements and string equality:
public static int getDaysInMonth(String month, int year) {
    if("January".equals(month) ||
       "March".equals(month)   ||
       "May".equals(month)     ||
       "July".equals(month)    ||
       "August".equals(month)  ||
       "October".equals(month) ||
       "December".equals(month))
        return 31;
    else if("April".equals(month)    ||
            "June".equals(month)     ||
            "September".equals(month)||
            "November".equals(month))
        return 30;
    else if("February".equals(month))
        return ((year % 4 == 0 && year % 100 != 0) ||
                 year % 400 == 0) ? 29 : 28;
    else
        throw new IllegalArgumentException("Invalid month: " + month);
}
The same code can be rewritten neatly using strings-in-switch as follows:
public static int getDaysInMonth2(String month, int year) {
    switch(month) {
        case "January":
        case "March":
        case "May":
        case "July":
        case "August":
        case "October":
        case "December":
            return 31;
        case "April":
        case "June":
        case "September":
        case "November":
            return 30;
        case "February":
            return ((year % 4 == 0 && year % 100 != 0) ||
                     year % 400 == 0) ? 29 : 28;
        default:
            throw new IllegalArgumentException("Invalid month: " + month);
    }
}
Further Reading:
Strings in switch Statements

Java 7: Underscores in Numbers and Binary Literals

In order to aid readability, you can now place underscores between numbers but you must start and end with a digit. For example:
int million = 1_000_000;
float pi = 3.14_159f;
JDK7 also allows you to express integer literals in binary form. This makes it easier to read code which uses bitwise operations. In order to do this, prefix your binary sequence with 0b or 0B. For example:
//previously, you would have had to do it like this:
int x = Integer.parseInt("1000", 2);

//in jdk7, you can create a binary literal like this:
int eight = 0b1000;

//easier to read bitwise operations
int four = 0b1000>>1;
Further Reading:
Underscores in Numeric Literals Binary Literals

Java 7: Multi-catch

You can now catch more than one exception in a single catch clause which removes redundant code.

Here is an example of a statement which throws multiple exceptions:

try {
    Class.forName("Object").newInstance();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}
In JDK7, you can collapse the catch blocks into a single one:
try {
    Class.forName("Object").newInstance();
} catch (ClassNotFoundException |
         InstantiationException |
         IllegalAccessException e) {
    e.printStackTrace();
}
Eclipse Support:
  • If you have multiple catch clauses, quick fix gives you the option to Combine catch blocks provided all the catch bodies are the same

  • Conversely, if you have a multi-catch clause, quick fix gives you the option to Use separate catch blocks so that you can handle each exception separately

  • Quick fix gives you the option to Move exception to separate catch block which allows you to take exceptions out of the multi-catch in case you want to handle them separately

  • Quick fix also gives you the option to Surround with try/multi-catch
Further Reading
Handling More Than One Type of Exception

Java 7: Diamond Operator

The diamond operator (<>) removes the need for explicit type arguments in constructor calls to generic classes, thereby reducing visual clutter. For example:
//previously:
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();

//in jdk7, use the diamond operator. Saves typing!
Map<Integer, List<String>> map2 = new HashMap<>();

List<?> list = new ArrayList<>();
The compiler infers the type on the right side. So if you have a list of ?, the compiler will infer a list of Object.

Eclipse support:

  • Eclipse Content Assist (Ctrl + Space), auto-completes using a diamond instead of explicit type arguments. So, in the example above, when you type new HashM[Ctrl+Space], Eclipse will insert new HashMap<>();.

  • You can also configure Eclipse to warn you if you use explicit type arguments, instead of a diamond. To do this, go to your Preferences and navigate to Java > Compiler > Errors/Warnings. In the Generic types section, select Warning against Redundant type arguments. Eclipse will then offer you a quick-fix to remove the type arguments, if you accidently put them in.
Further Reading:
Type Inference for Generic Instance Creation

Using Java 7 in Eclipse

1. Download Eclipse 3.7 Maintenance Build:
Eclipse 3.7 does not have support for Java 7, but the good news is that you can download a a 3.7 "maintenance build" (>= M20110729-1400) which does. I downloaded mine from here. The download was really slow, because it was coming from Canada and there were no other mirrors!

2. Add a Java 7 JRE:
Start Eclipse and go to Window > Preferences. Navigate to Java > Installed JREs and add your Java 7 JRE to the list, as the default JRE.

3. Upgrade Compiler Compliance Level:
Once again, in your preferences go to Java > Compiler and select 1.7 as the "Compiler compliance level".

4. Check Project JRE:
If you are working on an existing project, you need to make sure that the project is using JDK7 system library. Go into your project properties and into Java Build Path. Select the Libraries tab and check the version of your JRE System Library. If necessary, press Edit... to change it to JDK7.

5. Test it out:
Create a test class and use a Java 7 feature e.g. List<String> list = new ArrayList<>();. This should compile successfully. Eclipse should even be able to auto-complete the diamond.

The latest news on Eclipse Java 7 support can be found on the Eclipse wiki: http://wiki.eclipse.org/JDT/Eclipse_Java_7_Support_(BETA).

Friday, July 29, 2011

Java 7 is here!

I've been looking forward to Java 7 for a long time and it is finally here! This release is jam-packed with new features and I am really excited about trying it out!

There are great additions to the concurrency package such as a fork/join framework, phasers, transfer queues and threadlocal pseudo-random number generators.

Also, as part of Project Coin (JSR 334), JDK7 includes a set of small language changes intended to simplify common, day-to-day programming tasks and reduce boilerplate such as:

  • Strings in switch
  • Binary integral literals and underscores in numeric literals
  • Multi-catch and more precise rethrow
  • Improved Type Inference for Generic Instance Creation (diamond)
  • try-with-resources statement
  • Simplified Varargs Method Invocation
For a full list of changes take a look at the release notes.

I'm going to be writing about the new features in Java 7 as I learn about them, so stay tuned!