Subject: Core Java Technologies Tech Tips, March 15, 2005 (Generics, JConsole)

From: "SDN - Core Java Technologies Tech Tips" <[email-masked]>
Date: 15 Mar 2005 16:41:34 -0800

Core Java Technologies Tech Tips

                      Tips, Techniques, and Sample Code

Welcome to the Core Java Technologies Tech Tips for March 15, 
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:

         * Generics 
         * JMX, JConsole, and You
                           
These tips were developed using 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=816849411401630911:1110933044854.

This issue of the Core Java Technologies Tech Tips is written by 
John Zukowski, president of JZ Ventures, Inc. 
(http://www.jzventures.com).

You can view this issue of the Tech Tips on the Web at
http://java.sun.com/developer/JDCTechTips/2005/tt0315.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 latest Java platform releases, tutorials, and
newsletters.

java.net - A web forum for collaborating and building solutions 
together.

java.com - Hot games, cool apps -- Experience the power of Java 
technology. 

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GENERICS

The 5.0 release of J2SE includes the first set of significant 
language-level changes to the Java platform in some time. In 
addition to new constructs for things such as the enhance for 
loop and variable argument lists, J2SE 5.0 provides compile-time 
type safety with the Java Collections framework through generics
in accordance with JSR-14: Add Generic Types To The Java 
Programming Language
(http://www.jcp.org/en/jsr/detail?id=14).

One of the primary uses of generics is to abstract data types
when working with collections. Prior to the JDK 5.0 release, 
when you created a Collection, you could put anything in it, for
example:

   List myList = new ArrayList(10);
   myList.add(new Integer(10));
   myList.add("Hello, World");

If you wanted to restrict your Collection to a specific type, it 
was difficult at best. Getting items out of the collection 
required you to use a casting operation:

   Integer myInt = (Integer)myList.iterator().next();

If you accidently cast the wrong type, the program would 
successfully compile, but an exception would be thrown at 
runtime. Unless you dealt specifically with everything in the
Collection as an Object, casting typically happened blindly --
or by doing an instanceof check before calling the casted 
operation.

  Iterator listItor = myList.iterator();
  Object myObject = listItor.next();
  Integer myInt = null;
  if (myObject instanceof Integer) {
    myInt = (Integer)myObject;
  }
    
That situation underscores the beauty of generics. Generics 
allows you to specify, at compile-time, the types of objects you 
want to store in a Collection. Then when you add and get items 
from the list, the list already knows what types of objects are 
supposed to be acted on. So you don't need to cast anything. The 
"<>" characters are used to designate what type is to be stored. 
If the wrong type of data is provided, a compile-time exception 
is thrown. For example, if you try to compile the following 
class:

  import java.util.*;

  public class First {
    public static void main(String args[]) {
      List<Integer> myList = new ArrayList<Integer>(10);
      myList.add(10);
      myList.add("Hello, World");
    }
  }

you get an error like this:

   First.java:7: cannot find symbol
   symbol  : method add(java.lang.String)
   location: interface java.util.List<java.lang.Integer>
         myList.add("Hello, World");
               ^
   1 error

This message basically says that there is no add(String) method
available when the interface is for a List of Integer objects.
The myList.add(10); method did add the Integer object of number 
10 to the list. Autoboxing converted the int type to an Integer.
It is only the adding of a String to a List of Integer objects 
that failed here.

If you work with elements of a collection and don't explicitly
state the type of elements in that collection, you're warned 
about that, too. For instance, the following program creates 
a List, but it doesn't specify what type is to be stored in the 
List:

   import java.util.*;

   public class Second {
     public static void main(String args[]) {
       List list = new ArrayList();
       list.add(10);
     }
   }

When you compile the program, you get the following warning:

   Note: Second.java uses unchecked or unsafe operations.
   Note: Recompile with -Xlint:unchecked for details.

Yes, that is a warning. If you then follow the directions and 
add -Xlint:unchecked to the javac command line:

  javac -Xlint:unchecked Second.java

you will see the following added information:

  Second.java:6: warning: [unchecked] unchecked call to add(E) 
         as a member of the raw type java.util.List
    list.add(10);
            ^
The message means that the type of element added to the List, 
the "E" in the "add(E)" call, was never specified. The message 
is just a warning though, so a .class file was created.

If you want to get rid of the warning, you can add <Object> to
the List declaration, as follows:

    List<Object> list = new ArrayList<Object>();

Here, Object is the E, and basically says that anything can be 
stored in the List.

Where does E come from though?  If you look at the interface
declaration for java.util.List, you see the following:

   public interface List<E> extends Collection<E>

This literally says that it is declaring a List of E's.

Later in the interface definition, you see methods where the 
argument or return type is replaced by an E:

   Iterator<E> iterator();
   ListIterator<E> listIterator();
   boolean add(E o);
   boolean addAll(Collection<? extends E> c);

Because the E is specified at compile time, you don't have to
rely on runtime exceptions to find type mismatches. The ? in the
addAll line can be thought of as a collection of unknown, but 
the unknown would be E or a subclass. This construct allows you 
to work with collections of subclasses, and not simply exact 
matches.

Although not fully explored in the first example, generics is 
commonly used with the enhanced for loop, with an iterator. 
Without generics, looping through a List of String objects 
requires you to cast each element retrieved from the List to the 
appropriate type. However things get simpler with generics and 
the enhanced for loop.

Here's the old way of looping through a List of String objects, 
that is, without generics and an enhanced for loop:

   import java.util.*;

   public class Old {
     public static void main(String args[]) {
       List list = Arrays.asList(args);
       Iterator itor = list.iterator();
       while (itor.hasNext()) {
         String element = (String)itor.next();
         System.out.println(element + " / " + element.length());
       }
     }
   }
   
If you compile and run the Old class and then run it with 
a string, like this:

   java Old Hello
   
you get:

   Hello / 5
   
With JDK 5.0, you can combine the new enhanced for loop 
construct with generics to create a program that is type-safe at 
compile-time, and is more readable and more maintainable. Here's 
what looping through a List of String objects looks like if you 
use generics and an enhanced for loop:

   import java.util.*;

   public class New {
     public static void main(String args[]) {
       List<String> list = Arrays.asList(args);
       for (String element : list) {
         System.out.println(element + " / " + element.length());
       }
     }
   }
   
   java New Hello
   Hello / 5

As demonstrated here, generics and the enhanced for loop work 
well together.

For more information on generics, see:

o Tutorial: Generics in the Java Programming Language
  (http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf)
o "JSR-14: Add Generic Types To The Java Programming Language" 
  (http://jcp.org/en/jsr/detail?id=14)  
o "Generics" 
  (http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html).

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
JMX, JCONSOLE, AND YOU

JSR-160 (http://www.jcp.org/en/jsr/detail?id=160) defines an API 
that extends the Java Management Extensions (JMX) version 1.2 
APIs to provide remote access to JMX MBean servers. If you 
recall from the January 22, 2003 Tech Tip, "Getting Started with 
the Java Management Extensions (JMX)" 
(http://java.sun.com/developer/JDCTechTips/2003/tt0122.html#2),
you can carefully define components that can be monitored and 
managed through the JMX APIs. This monitoring and management 
capability is now a standard part of J2SE 5.0, and with JSR-160, 
there's now improved remote handling. For additional information 
on getting started with JMX, see the recent Enterprise Java
Technologies Tech Tip from Robert Eckstein, titled 
"Understanding JMX Technology" 
(http://java.sun.com/developer/EJTechTips/2005/tt0222.html#1).

In this tip, you'll take the code example in the earlier 
"Getting Started with JMX" tip, and update it for J2SE 5.0. 
You'll also learn how to use the new jconsole tool to display 
statistics for the running program.

In the earlier "Getting Started with JMX" tip, you needed to 
explicitly add JAR files to your classpath to compile and run 
the example program. However if you work with J2SE 5.0, you no 
longer have to explicitly add the JAR files to your classpath. 
That's because JMX is now a standard part of J2SE 5.0. All you
need to do is make a few changes to the original source, and the
program will compile and run with a standard Java development 
platform.

The MBean class in the earlier tip (HelloMBean) was packageless. 
It is always best to place your components in packages. To do 
that, create a directory for your source and add a package 
statement for that directory structure:

   package bean;

   public interface HelloMBean {
     public String getMessage();
     public void setMessage(String message);
     public int getChangeCount();
     public void resetCounter();
   }

Similarly, the only change to the MBean implementation (Hello) 
is to add the package statement:

   package bean;

   public class Hello implements HelloMBean {
     private String message;
     private int changeCount;
  
     public String getMessage() {
       return message;
     }
  
     public void setMessage(String message){
       this.message = message;
       changeCount++;
     }
  
     public int getChangeCount() {
       return changeCount;
     }
  
     public void resetCounter() {
       changeCount = 0;
     }
   }
 
The place where the more significant changes need to be made is 
in the agent (HelloAgent) that creates the component and 
registers it with the MBean server. You need to add the package 
statement here too. Also, you need to slightly change the way 
of getting the MBeanServer. J2SE 5.0 introduces the platform
MBeanServer which is designed for use by application MBeans as 
well as platform MBeans. It can serve as a single point of 
network publishing. It's recommended that applications use the
platform MBeanServer instead of creating their own. The old way
of getting the MBeanServer required importing the 
com.sun.jdmk.comm package and creating the server with a call to 
the createMBeanServer method of MBeanServerFactory:

     MBeanServer server = 
       MBeanServerFactory.createMBeanServer();
 
The new approach essentially does the same thing, but it allows 
all management resources to register in the single JMX agent 
(platform MBeanServer) instead of in multiple different ones. To 
get the platform MBeanServer, you need to call 
ManagementFactory.getPlatformMBeanServer and the 
ManagementFactory class is in java.lang.management package:

     MBeanServer server = 
       ManagementFactory.getPlatformMBeanServer();

Here's the updated version of HelloAgent:

   package bean;

   import java.lang.management.*;
   import javax.management.*;

   public class HelloAgent {
     public static void main(String args[]) {
       MBeanServer server = 
         ManagementFactory.getPlatformMBeanServer();
       HelloMBean hello1 = new Hello();
       HelloMBean hello2 = new Hello();
       try {
         ObjectName helloObjectName1 = new ObjectName(
           "bean:type=Hello,name=hello1");
         server.registerMBean(hello1, helloObjectName1);
         ObjectName helloObjectName2 = new ObjectName(
           "bean:type=Hello,name=hello2");
         server.registerMBean(hello2, helloObjectName2);
         System.out.println("Waiting...");
         Thread.sleep(Long.MAX_VALUE);
       } catch (InterruptedException e) {
         System.out.println("Sleep stopped");
         e.printStackTrace();
       } catch (MalformedObjectNameException e) {
         System.out.println("Bad object name");
         e.printStackTrace();
       } catch (InstanceAlreadyExistsException e) {
         System.out.println("Already exists");
         e.printStackTrace();
       } catch (MBeanRegistrationException e) {
         System.out.println("Registration problems");
         e.printStackTrace();
       } catch (NotCompliantMBeanException e) {
         System.out.println("Registration problems");
         e.printStackTrace();
       }
     }
   }

Now, let's look at the jconsole tool. JDK 5.0 includes a new 
Swing-based tool called jconsole that attaches to a running Java 
program and displays statistics about the program's performance, 
memory usage, and thread stack traces, as well as other MBean 
attributes and operations. One point worth mentioning is that 
with jconsole, you no longer need to create an HtmlAdaptorServer.

To use jconsole with the updated example program, you need to 
compile the three classes (HelloMBean, Hello, and HelloAgent) 
and then execute them with an appropriate command-line switch. 
When you compile the three classes, be sure to remember that 
they are in a package.

You can use the following command in the Windows environment to
compile the classes. Run the command from the parent directory
of the location where you created the classes, and replace 
"bean" with the actual name of location where you placed the 
files.

   javac bean\*.java

This places the .class files in the same directory as the source
files. If you want them in a different directory, use the 
-d option (but then you'll need to make sure the new location is 
in your classpath).

In the Solaris operating system or in a Linux or Mac environment, 
simply turn the slash around:

   javac bean/*.java
   
To execute a JMX-enabled program so that it can be monitored, 
you need to set the com.sun.management.jmxremote command line 
property:

   java -Dcom.sun.management.jmxremote HelloAgent

Because of the Thread.sleep() call at end of the main() method,
the method won't return immediately. At this point, you should
start the jconsole program. Before doing that, make sure the
HelloAgent program is running. To start jconsole, you have two
options. You can either discover the process id (PID) of the 
agent program with the new jps command-line tool, and pass that 
as a command-line option, or simply start jconsole without any 
options and it will find your program. To start jconsole without 
specifying a PID, enter the following command:

   jconsole

When started with no PID, the first thing you'll see is a window
labeled "JConsole: Connect to Agent". If HelloAgent is running,
you'll see it in the list. 

Select the agent and press Connect. This takes you to the initial
Summary screen.

The Memory, Threads, and Classes tabs have summary information 
on this first screen. You can also select these tabs to see
additional information.

The Memory tab allows you to chart heap memory usage and memory 
usage of each memory pool. You can also request a garbage 
collection call and see garbage collection run times.

The Threads tab lists the number of live threads. You can select
a specific thread in the list, and see its stack trace.

The Classes tab allows you to watch how many classes are loaded 
in the system at any one time. If you check the Verbose Output 
checkbox, output is dumped to the console as each additional 
class is loaded. These might be system generated classes, and 
not necessarily classes that you recognize.

The MBeans tab is essentially a replacement for the older 
browser-based Agent View. Here you can find your bean and modify
its attributes or execute its operations.

The final tab is labeled VM for virtual machine. It displays the 
details about your runtime platform as well as Operating System 
information.

One thing to keep in mind: your programs don't need to be or use 
MBeans to take advantage of the jconsole program. You can use 
jconsole with any program. Just be sure to start your program 
with the -Dcom.sun.management.jmxremote option before starting 
jconsole.

There's much more to JMX then what was covered in this tip. For
more information about JMX, see the following documents:

o Java Management Extensions (JMX) Technology Tutorial 
  (http://java.sun.com/j2se/1.5.0/docs/guide/jmx/tutorial/tutorialTOC.html).
o Monitoring and Management for the Java Platform
  (http://java.sun.com/j2se/1.5.0/docs/guide/management/)
o Using JConsole to Monitor Applications
  (http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html)

Also see the Java Management Extensions page 
(http://java.sun.com/products/JavaManagement/) for links to 
additional information and resources.
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing 
policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
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 JDC 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/developer/copyright.html

Core Java Technologies Tech Tips 
March 15, 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?816849411401630911