Subject: Core Java Technologies Tech Tips, May 5, 2005 (JDIC, Enhanced For Loop)

From: "SDN - Core Java Technologies Tech Tips" <[email-masked]>
Date: 5 May 2005 09:01:43 -0800

Core Java Technologies Tech Tips

                      Tips, Techniques, and Sample Code

Welcome to the Core Java Technologies Tech Tips for May 5, 2005. 
Here you'll get tips on using core Java technologies and APIs, 
such as those in Java 2 Platform, Standard Edition (J2SE).

This issue covers:

          * Communicating With Native Applications Using JDIC    
          * The Enhanced For Loop
            
These tips were developed using the Java 2 Platform Standard 
Edition Development Kit 5.0 (JDK 5.0). You can download JDK 5.0
at http://enews.sun.com/CTServlet?id=84830600-587776814:1115308360618.

This issue of the Core Java Technologies Tech Tips is written by
Daniel H. Steinberg, Director of Java Offerings for Dim Sum
Thinking, Inc, and editor-in-chief for java.net (http://java.net).

You can view this issue of the Tech Tips on the Web at
http://java.sun.com/developer/JDCTechTips/2005/tt0505.html.

See the Subscribe/Unsubscribe note at the end of this newsletter
to subscribe to Tech Tips that focus on technologies and products
in other Java platforms.

For more Java technology content, visit these sites:

java.sun.com - The Java technology source for developers. Get the 
latest Java platform releases, tutorials, newsletters and more.

java.net - A web forum where enthusiasts of Java technology can 
collaborate and build solutions together.

java.com - The ultimate marketplace promoting Java technology, 
applications and services. 

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
COMMUNICATING WITH NATIVE APPLICATIONS USING JDIC

JDesktop Integration Components (JDIC) 
(https://jdic.dev.java.net) enable Java applications to 
integrate into the native desktop. This allows these 
applications to take advantage of functionality provided by 
operating system-specific programs such as web browsers or email 
tools. JDIC is currently supported in the Solaris 8 (or later) 
Operating System, the Sun Java Desktop System (JDS) Release 1 or 
later, various Windows operating systems (ME, NT, XP, 2003, and 
2000), SuSE Linux 7.1 or later, and RedHat Linux 8 or later. 
Support for Mac OS X is being added for future releases.

In this tip you will load a web page using the JEditorPane and
consider some of the limitations of this approach. You will then
use two different features of JDIC to view the web page (as part 
of a JFrame) in your existing web browser. 

You can display HTML in many Swing components. For example, you 
can use a JEditorPane to display HTML like this:

   private void loadStartingPage() {
     JEditorPane editor = new JEditorPane();
     editor.setEditable(false);
     try {
       editor.setPage("http://www.java.net/");
     } catch (IOException e) {
       System.err.println("can't connect");
     }
   }

If the URL is reachable, the resulting page should be displayed 
in the JEditorPane. Of course, you will have to provide a JFrame 
that contains a JScrollPane that, in turn, contains the 
JEditorPane. For thread safety, you should also create the GUI 
by scheduling a job on the event-dispatching thread. All of this 
is shown in the following class:

   import javax.swing.JScrollPane;
   import javax.swing.JEditorPane;
   import javax.swing.JFrame;
   import javax.swing.SwingUtilities;
   import java.io.IOException;
   import java.awt.Dimension;

   public class EditorPaneHTMLViewer extends JEditorPane {
     private JScrollPane createScrollPane() {
       JScrollPane editorScrollPane = new JScrollPane(this);
       editorScrollPane.setPreferredSize(
               new Dimension(700, 500));
       return editorScrollPane;
     }

     private void loadStartingPage() {
       setEditable(false);
       try {
         setPage("http://www.java.net/");
       } catch (IOException e) {
         System.err.println("can't connect");
       }
     }

     private void createAndShowGUI() {
       JFrame frame = new JFrame("EditorPaneHTMLViewer");
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       JScrollPane content = createScrollPane();
       loadStartingPage();
       frame.add(content);
       frame.pack();
       frame.setVisible(true);
     }

     public static void main(String[] args) {
       //Schedule a job for the event-dispatching thread:
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           (new EditorPaneHTMLViewer()).createAndShowGUI();
         }
       });
     }
   }

The good news is that when you compile and run this program, the
resulting HTML is displayed in the JEditorPane. But you can also 
see that the current level of HTML support is not sufficient to 
properly display many modern standards-compliant pages.

It's unfortunate that even with a perfectly good web browser
installed, you are not be able to properly view web pages in 
a Swing component such as a JEditorPane. However, JDIC gives you
a way to do this. You open your default web browser to 
a specified page by calling the browse() method in one of the
JDIC packages, org.jdesktop.jdic.desktop.Desktop. When you call
the browse() method, you need to pass in a java.net.URL object,
as shown in the following example:

   import org.jdesktop.jdic.desktop.Desktop;
   import org.jdesktop.jdic.desktop.DesktopException;
   import java.net.URL;
   import java.net.MalformedURLException;

   public class OpenWithRegisteredApp {

     public static void main(String[] args) {
       try {
         Desktop.browse(new URL("http://www.java.net/"));
       } catch (MalformedURLException e){
         System.err.println("couldn't connect");
         e.printStackTrace();
       } catch (DesktopException e){
         e.printStackTrace();
       }
     }
   }

To compile the example program, you need to include the jdic.jar 
file in your class path. To run the program, you need the native 
libraries included in a place where the JVM can find it. 
Alternatively, you can point to the jar file and the native 
libraries at runtime by using -Djava.library.path= followed by 
the path to the directory that contains the native libraries. 
For example, on a Windows machine, if you copy the jar file and 
dll files into the same directory as the one that contains your 
program, you can use the following command to run the program:

   java -classpath jdic.jar;. -Djava.library.path=. 
   OpenWithRegisteredApp
   
Note that the command is shown on two lines for formatting 
purposes. You should enter the command on one line.

As a result, your default browser should open and load the front
page of java.net.

The JDIC APIs also provide support for other operations you 
would want to perform to access and interact with native desktop
applications. You can launch an editor to edit a specified file.
You can launch a window to compose a new message in the default
mailer, optionally filling in some of the fields in the mail
message. You can launch the registered application for a given
file or print the contents of a file. The details of using these
methods are similar to the way in which browse() was used
in the OpenWithRegisteredApp example. 

There are times, however, when you might prefer to display a web
page from inside your Java application. Instead of bringing up 
an external web browser, you might want to show the web content 
in your JFrame without having to revert to the primitive look of 
the JEditorPane. Another JDIC component, the 
org.jdesktop.jdic.browser.WebBrowser class, was created for that 
reason. WebBrowser extends java.awt.Canvas and can be added 
directly to your JFrame. Here is an example that uses the 
WebBrowser class.

   import org.jdesktop.jdic.browser.WebBrowser;
   import javax.swing.JFrame;
   import javax.swing.SwingUtilities;
   import java.net.URL;
   import java.net.MalformedURLException;
   import java.awt.Dimension;

   public class JDICBrowser {

     private WebBrowser webBrowser = new WebBrowser();

     private void loadStartingPage() {
       try {
         webBrowser.setURL(new URL("http://www.java.net"));
       } catch (MalformedURLException e) {
         System.out.println(e.getMessage());
       }
     }

     private void createAndShowGUI() {
       JFrame frame = new JFrame("JDIC Browser");
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.setPreferredSize(new Dimension(700,500));
       loadStartingPage();
       frame.add(webBrowser);
       frame.pack();
       frame.setVisible(true);
     }

     public static void main(String[] args) {
       //Schedule a job for the event-dispatching thread:
       SwingUtilities.invokeLater(new Runnable() {
         public void run() {
           (new JDICBrowser()).createAndShowGUI();
         }
       });
     }
   }

Although this code looks a lot like the first version, the result
is a properly rendered view of the web page.

You can add a text field and buttons to either this version or
the first version. This allows the user to enter the URL of 
other pages and to navigate through the history. You can also 
take advantage of callbacks to provide a better user experience 
by implementing the WebBrowserListener class. Here, for example, 
is an adapter class that implements two of the methods.

   import org.jdesktop.jdic.browser.WebBrowserListener;
   import org.jdesktop.jdic.browser.WebBrowserEvent;

   public class WebBrowserAdapter implements WebBrowserListener {
     public void downloadStarted(WebBrowserEvent e){
       System.out.println("Download Started");
     }
     public void downloadCompleted(WebBrowserEvent e){
       System.out.println("Download Completed");
     }
     public void downloadProgress(WebBrowserEvent e){}
     public void downloadError(WebBrowserEvent e){}
     public void documentCompleted(WebBrowserEvent e){}
     public void titleChange(WebBrowserEvent e){}
     public void statusTextChange(WebBrowserEvent e){}
   }

You can add this WebBrowserListener by modifying the
createAndShowGUI() method as follows:

   //...
   loadStartingPage();
   // add the following line:
   webBrowser.addWebBrowserListener(new WebBrowserAdapter());
   ...

When you rerun JDICBrowser you will see the feedback in standard 
out as downloads begin and complete.

   C:\techtips\May05>java JDICBrowser
   Download Started
   Download Completed
   Download Started
   Download Started
   Download Completed

The point of this tip is not to demonstrate how to build 
a better browser. Instead the intent is to show you how to 
easily integrate native components using the classes in the JDIC 
open source project. More features are being added, and the 
project owners would welcome your contributions.

You can learn more about JDIC on the JDIC project page 
(https://jdic.dev.java.net). Also see George Zhang's blog entry 
on this topic 
(http://weblogs.java.net/blog/georgez/archive/2005/03/wheres_jdic_goi.html).

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
THE ENHANCED FOR LOOP

Introduced as a new language feature in J2SE 5.0, the enhanced
for loop allows you to iterate through a collection without
having to create an Iterator or without having to calculate
beginning and end conditions for a counter variable. The 
enhanced for loop is the easiest of the new features to 
immediately incorporate in your code. In this tip you will see 
how the enhanced for loop replaces more traditional ways of 
sequentially accessing elements in a collection.

So what does an enhanced for loop look like? Suppose you have 
a collection of TechTip objects called RecentTips. You could 
use an enhanced for loop with the collection as follows:

   for (TechTip tip: RecentTips)

You read this as "for each TechTip in RecentTips". Here the 
variable tip is used to point to the current instance of TechTip 
in the collection. Because of the "for each" wording, the 
enhanced-for construct is also referred to as the for-each 
construct. 

If you compare the enhanced for loop to the typical way of 
iterating over a collection, it's clear that the for each 
loop is simpler and can make your code more readable. 

Also note that the enhanced for loop is designed to simplify 
your work with generics. Although this tip does include two
examples of using the enhanced for loop with generics, it's
not the focus of the tip. Instead the objective of this tip is 
to introduces you to the more basic changes you can make to 
your code to use the for each loop.

First, consider how you might use a for loop to iterate through 
the elements of an Array. For simplicity, load an array with six 
ints that represent the squares of the ints from zero to five. 
Here's a for loop that does the iteration:

   for (int i=0; i< squares.length; i++)
   
The line illustrates the classic use of the for loop. It 
specifies the initial value of one or more counters, sets up 
a terminating condition, and describes how the counters might be 
incremented.

Here is a short program, OldForArray, that uses the for loop. 

   public class OldForArray {

     public static void main(String[] args){
       int[] squares = {0,1,4,9,16,25};
       for (int i=0; i< squares.length; i++){
         System.out.printf("%d squared is %d.\n",i, squares[i]);
       }
     }
   }

Compile and run the OldForArray program, and you get the 
following:

   0 squared is 0.
   1 squared is 1.
   2 squared is 4.
   3 squared is 9.
   4 squared is 16.
   5 squared is 25.

If you change the test program to use the enhanced for loop, you 
specify the relevant variable and the collection that the 
variable comes from. Here is a line that's an enhanced for loop:

    for (int i : squares)
    
You can read the line as "iterate on elements from the 
collection named squares." The current element will be referenced 
by the int i."

You don't need to determine how many elements are in the array
before looping. There is also no need to specify how to 
increment the current position. "Under the covers," the enhanced 
for loop for an array is equivalent to the for loop presented 
earlier.

The test program NewForArray gives the same result as 
OldForArray.

   public class NewForArray {

     public static void main(String[] args) {
       int j = 0;
       int[] squares = {0, 1, 4, 9, 16, 25};
       for (int i : squares) {
         System.out.printf("%d squared is %d.\n", j++, i);
       }
     }
   }

An array is an indexed collection of elements of a single type
that is specified when the array is declared. With more general
collections such as ArrayLists, the elements are stored as
Objects. You could use the C style for loop to iterate through a
collection like this:

   for (int i = 0; i < list.size(); i++)

You then can use list.get(i) to reference the current element.
For example, the following program, OldForArrayList, uses 
autoboxing to fill the ArrayList and to then read from the 
ArrayList:

   import java.util.ArrayList;
   import java.util.List;

   public class OldForArrayList {
     private static List squares = new ArrayList();

     private static void fillList() {
       for (int i = 0; i < 6; i++) {
         squares.add(i * i);
       }
     }

     private static void outputList() {
       for (int i = 0; i < squares.size(); i++) {
         System.out.printf("%d squared is %d.\n",
           i, squares.get(i));
       }
     }

     public static void main(String args[]) {
       fillList();
       outputList();
     }
   }

However, because ArrayList is part of the collections 
framework, it is more common to iterate through it using an 
Iterator in the following pattern:

   while( iterator.hasNext()) {
     doSomethingWith (iterator.next());
   }

You can bundle this in a for loop as shown in the following 
program, IteratorForArrayList:

   import java.util.ArrayList;
   import java.util.List;
   import java.util.Iterator;

   public class IteratorForArrayList {

     private static List squares = new ArrayList();

      private static void fillList() {
       for (int i = 0; i < 6; i++) {
         squares.add(i * i);
       }
     }

     private static void outputList() {
       Iterator iterator = squares.iterator();
       int j=0;
       for (; iterator.hasNext();) {
         System.out.printf("%d squared is %d.\n",
                            j++, iterator.next());
       }
     }

     public static void main(String args[]) {
       fillList();
       outputList();
     }
   }

It looks a bit unusual to have a for loop with no first or third
parameter. There is no initial condition, and the incrementing 
of the position in the List is performed in the body of the for 
loop with the call iterator.next().

The enhanced for loop makes the explicit use of an iterator
unnecessary. Rather than create an Iterator object for the 
ArrayList and then use the iterator in the for loop, you use the 
following:

   for ( Integer square : squares)

This indicates that the name of the collection is squares. It
also indicates that the currently referenced item is of type 
Integer and is referenced by the variable square.

This code will not compile because there is no way of knowing
that the contents of the ArrayList is of type Integer. To fix
this, you need to use another feature introduced in J2SE 5.0, 
namely generics. You need to specify in the declaration and 
definition of squares that it can only hold elements of type 
Integer. You do this as follows:

   private static List<Integer> squares
                               = new ArrayList<Integer>();

The following program, NewArrayList, shows how to use the 
enhanced for loop together with generics:

   import java.util.List;
   import java.util.ArrayList;

   public class NewArrayList {
     private static List<Integer> squares
                               = new ArrayList<Integer>();

      private static void fillList() {
       for (int i = 0; i < 6; i++) {
         squares.add(i * i);
       }
     }

     private static void outputList() {
       int j=0;
       for (Integer square : squares) {
         System.out.printf("%d squared is %d.\n",
                         j++, square);
       }
     }

     public static void main(String args[]) {
       fillList();
       outputList();
     }
   }

This NewArrayList example is a bit simplistic, but it 
demonstrates the syntactic differences between using the classic 
for loop and the enhanced for loop. Here is another example
that compares the syntactic differences between the loops. The
example is excerpted from a talk given by Joshua Bloch and 
Neil Gafter at the 2004 JavaOne Conference. In the example, 
a method is applied to each element in a collection. To start, 
the example uses an Iterator like this:

   void cancelAll (Collection c) {
     for (Iterator i = c.iterator(); i.hasNext(); ) {
       TimerTask tt = (TimerTask) i.next();
       tt.cancel();
     }
   }

Next, an enhanced for loop is introduced to eliminate the use of 
the Iterator:

   void cancelAll( Collection c ) {
     for (Object o : c)
       ( (TimerTask) o). cancel();
   }

There is still a matter of having to treat the elements of the
collection as being of type Object and then casting them to type
TimerTask. This is fixed by introducing generics like this:

   void cancelAll( Collection<TimerTask> c ) {
     for (TimerTask task : c)
       task.cancel();
   } 

It's important to note that the enhanced for loop can't be used 
everywhere. You can't use the enhanced for loop: 

o To remove elements as you traverse collections
o To modify the current slot in an array or list
o To iterate over multiple collections or arrays

However aside from these cases, you should try to use the 
enhanced for loop code to simplify your code.

As with anything new, the syntax for the enhanced for loop might 
seem unfamiliar and difficult to read. You have probably used 
the C style for loop for many years and possibly in more than 
one language. It is, however, cleaner not having to create 
a counter variable or an Iterator. You also do not need to worry 
about where your collection begins and ends to set up the 
initial value and loop termination conditions. 

For more information on the enhanced for loop, see "The For-Each
Loop" 
(http://java.sun.com/j2se/1.5.0/docs/guide/language/foreach.html).

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  
TRY THE NEW SEARCH FACILITY

Sun is working on a new search facility for its developer sites. 
The search facility is currently available as a beta release. 
Try it out and provide your feedback. You can access the search 
facility at 
http://onesearch.sun.com/search/onesearch/index.jsp?col=developer-all&qt=java 

.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

PRIVACY STATEMENT:
Sun respects your online time and privacy (http://sun.com/privacy).
You have received this based on your e-mail preferences. If you 
would prefer not to receive this information, please follow the 
steps at the bottom of this message to unsubscribe. 

Please read our Terms of Use and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://developers.sun.com/dispatcher.jsp?uid=6910008

* FEEDBACK
  Comments? Please enter your feedback on the Tech Tips at: 
  
     http://developers.sun.com/contact/feedback.jsp?category=sdn

* SUBSCRIBE/UNSUBSCRIBE

  Subscribe to other Java developer Tech Tips:
  
  - Enterprise Java Technologies Tech Tips. Get tips on using
    enterprise Java technologies and APIs, such as those in the
    Java 2 Platform, Enterprise Edition (J2EE).    
  - Wireless Developer Tech Tips. Get tips on using wireless
    Java technologies and APIs, such as those in the Java 2 
    Platform, Micro Edition (J2ME).
    
  To subscribe to these and other SDN publications:
  - Go to the Sun Developer Network - Subscriptions page,
    (https://softwarereg.sun.com/registration/developer/en_US/subscriptions), 
    choose the newsletters you want to subscribe to and click 
    "Submit".
  - To unsubscribe, go to the Subscriptions page,
    (https://softwarereg.sun.com/registration/developer/en_US/subscriptions), 
    uncheck the appropriate checkbox, and click "Submit".

  - To use our one-click unsubscribe facility, see the link at 
    the end of this email:
    
- ARCHIVES
You'll find the Core Java Technologies Tech Tips archives at:

http://java.sun.com/developer/TechTips/index.html

- COPYRIGHT
Copyright 2005 Sun Microsystems, Inc. All rights reserved.
4150 Network Circle, Santa Clara, California 95054 USA.

This document is protected by copyright. For more information, see:

http://java.sun.com/jdc/copyright.html

Core Java Technologies Tech Tips 
May 5, 2005

Trademark Information: http://www.sun.com/suntrademarks/
Java, J2SE, J2EE, J2ME, and all Java-based marks are trademarks 
or registered trademarks of Sun Microsystems, Inc. in the
United States and other countries.

To use our one-click unsubscribe facility, select the following URL:
http://subscriptions.sun.com/unsubscribe?84830600-587776814