Thứ Bảy, 9 tháng 10, 2010

New Links to My Oracle Technology Network Articles

I noticed that the URLs to Oracle Technology Network (OTN) articles have changed recently. In this brief post, I list the new URLs for the articles that I have written or co-written that are published on OTN.

Build a Java Application With Eclipse, Spring, and Oracle WebLogic Server (February 2010)
New URL: http://www.oracle.com/technetwork/articles/marx-oepe-spring-095718.html
Former URL: http://www.oracle.com/technology/pub/articles/marx-oepe-spring.html

Basic Java Persistence API Simple Best Practices (May 2008)
New URL: http://www.oracle.com/technetwork/articles/marx-jpa-087268.html
Former URL: http://www.oracle.com/technology/pub/articles/marx-jpa.html

Visualize Your Oracle Database Data with JFreeChart (October 2007)
New URL: http://www.oracle.com/technetwork/articles/marx-jchart-085298.html
Former URL: http://www.oracle.com/technology/pub/articles/marx-jchart.html

Better JPA, Better JAXB, and Better Annotations Processing with Java SE 6 (September 2007)
New URL: http://www.oracle.com/technetwork/articles/marx-jse6-090753.html
Former URL: http://www.oracle.com/technology/pub/articles/marx-jse6.html

Accessorize Oracle Database with Ruby (February 2007)
New URL: http://www.oracle.com/technetwork/articles/marx-ruby-092465.html
Former URL: http://www.oracle.com/technology/pub/articles/marx-ruby.html

Add Some Spring to Your Oracle JDBC Database Access (November 2005)
New URL: Unknown (see this Internet Archive Wayback Machine Copy)
Former URL: http://www.oracle.com/technetwork/articles/marx_spring.html

Thứ Ba, 5 tháng 10, 2010

javac's -Xprint Option

With ready accessibility to the Java SDK API documentation and Java EE API documentation online and with the convenience of IDE method name completion, it is often easy to determine a class's public exposed API. However, even with these great tools at hand, I always like to be aware of useful command-line tools to supplement these tools. Such knowledge can be particularly useful if in an environment where the online documentation or properly working IDE are not as easily available or are less desirable because of their overhead. The Sun/Oracle javac compiler supports the non-standard (and hence not guaranteed to be in other Java compiler implementations or even in future Oracle javac implementations) -Xprint option to make this easy. A side benefit of this option is for generating a textual representation of a class's API.

The javac documentation describes the -Xprint option: "Print out textual representation of specified types for debugging purposes; perform neither annotation processing nor compilation. The format of the output may change."

The output of -Xprint on a .class file looks very similar to javap's output. For example, javac -Xprint shows the following output when run against java.lang.Object:

javac -Xprint java.lang.Object
package java.lang;

public class Object {

public Object();

private static native void registerNatives();

public final native java.lang.Class getClass();

public native int hashCode();

public boolean equals(java.lang.Object arg0);

protected native java.lang.Object clone() throws java.lang.CloneNotSupportedException;

public java.lang.String toString();

public final native void notify();

public final native void notifyAll();

public final native void wait(long arg0) throws java.lang.InterruptedException;

public final void wait(long arg0,
int arg1) throws java.lang.InterruptedException;

public final void wait() throws java.lang.InterruptedException;

protected void finalize() throws java.lang.Throwable;
}

Compare the above output from javac -Xprint on java.lang.Object to the output (shown next) of running javap against java.lang.Object:


Compiled from "Object.java"
public class java.lang.Object{
public java.lang.Object();
public final native java.lang.Class getClass();
public native int hashCode();
public boolean equals(java.lang.Object);
protected native java.lang.Object clone() throws java.lang.CloneNotSupportedException;
public java.lang.String toString();
public final native void notify();
public final native void notifyAll();
public final native void wait(long) throws java.lang.InterruptedException;
public final void wait(long, int) throws java.lang.InterruptedException;
public final void wait() throws java.lang.InterruptedException;
protected void finalize() throws java.lang.Throwable;
static {};
}

Of course, the output above is shown with javap's default settings. The private and protected members can be displayed using javap's -private and -protected options.

One advantage of javac -Xprint, however, is that the -Xprint option can be easily used with javac if one wants to see the interface for multiple files. The javac compiler can be used as normal against the normal source code files, but with the -Xprint option specified, the interfaces will be printed out without actually compiling the code. This is demonstrated here. I add the -Xprint option to my javac compiler when compiling the examples from my last blog post on javac -Xlint and get the following output:

package dustin.examples;

/**
* Simple class intended to help demonstrate -Xlint:overrides by providing a
* method that won't be overridden quite the same by its child.
*/
public class BaseClass {
protected java.util.List<java.lang.String> names;

public BaseClass();

public void addNames(final java.lang.String[] newNames);
}
package dustin.examples;

/**
* Simple class intended to help demonstrate -Xlint:overrides by "sort of"
* overriding a method defined in its parent.
*/
public class ChildClass extends dustin.examples.BaseClass {

public ChildClass();

@java.lang.Override
public void addNames(final java.lang.String... newNames);
}
package dustin.examples;

/**
* Simple Color representation.
*/
public enum Color {

BLACK,
BLUE,
BROWN,
CORAL,
EGGSHELL,
GREEN,
MAUVE,
ORANGE,
PINK,
PURPLE,
RED,
TAN,
WHITE,
YELLOW;
public static dustin.examples.Color[] values();

public static dustin.examples.Color valueOf(java.lang.String name);

private Color();
}
package dustin.examples;

/**
* Gender.
*/
public enum Gender {

FEMALE,
MALE;
public static dustin.examples.Gender[] values();

public static dustin.examples.Gender valueOf(java.lang.String name);

private Gender();
}
package dustin.examples;

/**
* Main executable demonstrating HotSpot's non-standard Xlint warning flags.
*/
public class Main {

public Main();
/**
*Fred.
*/
private static final dustin.examples.Person fred;
/**
*Wilma.
*/
private static final dustin.examples.Person wilma;
/**
*Barney.
*/
private static final dustin.examples.Person barney;

/**
* Demonstrates -Xlint:cast warning of a redundant cast.
*/
private static void demonstrateCastWarning();

/**
* Cause -Xlint:deprecation to print warning about use of deprecated method.
*/
private static void demonstrateDeprecationWarning();

/**
* Cause -Xlint:fallthrough to print warning about use of switch/case
* fallthrough.
*/
private static void demonstrateFallthroughWarning();

/**
* Demonstrate -Xlint:finally generating warning message when a {@code finally}
* block cannot end normally.
*/
private static void demonstrateFinallyWarning();

/**
* Divide the provided divisor into the provided dividend and return the
* resulting quotient. No checks are made to ensure that divisor is not zero.
* @param dividend Integer to be divided.
* @param divisor Integer by which dividend will be divided.
* @return Quotient of division of dividend by divisor.
*/
private static double divideIntegersForDoubleQuotient(final int dividend,
final int divisor);

/**
* Demonstrate -Xlint:divzero in action by dividing an int by a literal zero.
*/
private static void demonstrateDivideByZeroWarning();

/**
* Surprisingly, there is no -Xlint warning option for this highly
* suspicious situation of passing an object to a Set.contains call that
* could not possibly hold that type of object (could never result to true).
*/
private static void demonstrateNoContainsWarning();

/**
* This method demonstrates how javac's -Xlint:empty works. Note that javac's
* -Xlint:empty will only flag the empty statement involved in the "if" block,
* but does not flag the empty statements associated with the do-while loop,
* the while loop, the for loop, or the if-else. NetBeans does flag these if
* the appropriate "Hints" are turned on.
*/
private static void demonstrateEmptyWarning();

/**
* Divide the provided divisor into the provided dividend and return the
* resulting quotient. No checks are made to ensure that divisor is not zero.
* @param dividend Integer to be divided.
* @return Quotient of division of dividend by divisor.
*/
private static long divideIntegerByZeroForLongQuotient(final int dividend);

/**
* Demonstrate the commonly seen -Xlint:unchecked in action.
* @return Set of Person objects.
*/
private static java.util.Set<dustin.examples.Person> demonstrateUncheckedWarning();

/**
* Main executable function to demonstrate -Xlint. Various -Xlint options
* are demonstrated as follows:
* <ul>
* <li>{@code -Xlint:cast}</li>: This class's method demonstrateCastWarning()
* demonstrates how a redundant cast can lead to this warning.</li>
* <li>{@code -Xlint:deprecation}: This class's method demonstrateDeprecationWarning()
* intentionally invokes a deprecated method in the Person class.</li>
* <li>{@code -Xlint:divzero}: This class's demonstrateDivideByZeroWarning()
* method demonstrates this warning generated when a literal zero is
* used as a divisor in integer division.</li>
* <li>{@code -Xlint:empty}: This class's demonstateEmptyWarning() method
* demonstrates that (likely accidental) "if" expression without any
* result of the condition being {@code true} being performed results in
* a warning this option's set.
* <li>{@code -Xlint:fallthrough}: This class's method demonstrateFallthroughWarning()
* demonstrates how {@code switch} statements with {@code case} expressions
* without their own {@code break} statements may or may not lead to
* this producing a warning message.</li>
* <li>{@code -Xlint:finally}: This class's method demonstrateFinallyWarning()
* demonstrates the warning related to a return from a {@code finally}
* clause.</li>
* <li>{@code -Xlint:overrides}: This is demonstrated in classes external to
* this one: {@code BaseClass} and its child class @{code ChildClass}.</li>
* <li>{@code -Xlint:path}: This is shown by providing a path to the javac
* compiler's classpath option for a location that does not exist.</li>
* <li>{@code -Xlint:serial}: The Person class implements the Serializable
* interface, but does not declare an explicit serialVersionUID.</li>
* <li>{@code -Xlint:unchecked}: This class's demonstrateUncheckedWarning()
* demonstrates this warning message.</li>
* </ul>
* @param arguments Command-line arguments: none expected.
*/
public static void main(final java.lang.String[] arguments);
}
package dustin.examples;

/**
* Person class that intentionally has problems that will be flagged as warnings
* by javac with -X non-standard options.
*/
public final class Person implements java.io.Serializable {
private final java.lang.String lastName;
private final java.lang.String firstName;
private final dustin.examples.Gender gender;
private final dustin.examples.Color favoriteColor;

public Person(final java.lang.String newLastName,
final java.lang.String newFirstName,
final dustin.examples.Gender newGender,
final dustin.examples.Color newFavoriteColor);

public java.lang.String getLastName();

public java.lang.String getFirstName();

public java.lang.String getFullName();

/**
* Provide the person's full name.
* @return Full name of this person.
* @deprecated Use getFullName() instead.
*/
@java.lang.Deprecated
public java.lang.String getName();

public dustin.examples.Gender getGender();

public dustin.examples.Color getFavoriteColor();

/**
* NetBeans-generated equals(Object) method checks for equality of provided
* object to me.
* @param obj Object to be compared to me for equality.
* @return {@code true} if the provided object and I are considered equal.
*/
@java.lang.Override
public boolean equals(java.lang.Object obj);

/**
* NetBeans-generated hashCode() method.
* @return Hash code for this instance.
*/
@java.lang.Override
public int hashCode();

@java.lang.Override
public java.lang.String toString();
}

The output of my own classes shown above is a reminder of another nicety of javac -Xprint: it includes the Javadoc comments of the members and methods that it prints out when source code is available. This can be helpful in understanding what the parameters of the API methods are. If javac -Xprint is run directly against a .class file, it does not include the Javadoc comments; if it's run against the .java source file, it does include the Javadoc comments.

For example, if I change my directory to the installation directory of the Spring Framework, I can use the command
javac -Xprint src\org\springframework\core\Constants.java
to see the org.springframework.core.Constants class members and methods with accompanying Javadoc comments. Alternatively, I could run javac -Xprint against the compiled .class file as well (but won't see the Javadoc comments in that output) with the command

javac -cp dist\spring.jar -Xprint org.springframework.core.Constants

It is nice to be able to run javac -Xprint against compiled binaries (.class) or raw source (.java).

Another interesting facet of the javac -Xprint is that it demonstrates what annotation processors can do in Java SE 6.

I usually use an IDE and the online Javadoc-based API documentation to learn new APIs or remind myself of the specifics of APIs I don't use frequently. However, every once in a while, I find it useful to be aware of the existence of javap and of javac -Xprint for providing a quick reminder of the available APIs on my own classes and on third-party classes.

Thứ Hai, 4 tháng 10, 2010

javac's -Xlint Options

The Java programming language compiler (javac) provided by Oracle (and formerly by Sun) has several non-standard options that are often useful. One of the most useful is the set of non-standard options that print out warnings encountered during compilation. That set of options is the subject of this post.

The javac page section on non-standard options lists and provides brief details on each of these options. The following is the relevant snippet from that page.


A listing of these options is also available from the command line (assuming the Java SDK is installed) with the command: javac -help -X. This is briefer than the man page/web page example shown above and is shown next.


As the previous snapshot from running javac -help -X indicates, the ten specific conditions for which Xlint warnings exist are (in alphabetical order): cast, deprecation, divzero, empty, fallthrough, finally, overrides, path, serial, and unchecked. I briefly look at each of these and provide a code snippet that leads to these warning occurring when Xlint is turned on. Note that the man page for javac and the Java SE 6 javac page both only list half of these Xlint options (documentation is apparently not as up-to-date as the javac usage/help). There is a useful NetBeans Wiki entry that summarizes all ten options.

The javac compiler allows all or none of the Xlint warnings to be enabled. If Xlint is not specified at all of the option -Xlint:none is explicitly specified, the behavior is to not show most of the warnings. Interestingly, the output does provide a warning about deprecation and unchecked warnings and recommends running javac with -Xlint enabled to see the details on these two types of warnings.

Before the end of this post, I'll demonstrate Java code that leads to 13 total reported Xlint warnings covering all ten of the options discussed above. However, without Xlint specified, the output is as shown in the next screen snapshot.


As the above image indicates, whether Xlint is not specified at all or is specified explicitly with "none", the result is the same: the majority of the warnings are not shown, but there are simple references to the deprecation and unchecked warnings with recommendations to run javac with -Xlint:deprecation and -Xlint:unchecked respectively for additional details. Running javac with -Xlint:all or -Xlint with no other options will show all warnings and would work to see the details regarding deprecated, unchecked, and all other applicable Xlint-enabled warnings. This will be shown after going through the source code and each Xlint warning individually.

-Xlint:cast
This option can be used to have the compiler warn the developer that a redundant cast is being made. Here is a code snippet that would get flagged if -Xlint, -Xlint:all, or -Xlint:cast was provided to javac when compiling the source.

/**
* Demonstrates -Xlint:cast warning of a redundant cast.
*/
private static void demonstrateCastWarning()
{
final Set<Person> people = new HashSet<Person>();
people.add(fred);
people.add(wilma);
people.add(barney);
for (final Person person : people)
{
// Redundant cast because generic type explicitly is Person
out.println("Person: " + ((Person) person).getFullName());
}
}

In the above code, there is no need to cast the person object inside the for loop to Person and -Xlint:cast will warn of this unnecessary and redundant cast with a message stating something like:
src\dustin\examples\Main.java:37: warning: [cast] redundant cast to dustin.examples.Person
out.println("Person: " + ((Person) person).getFullName());
^


-Xlint:deprecation
As discussed above, the Xlint deprecation warning was evidently deemed important enough to justify it being advertised even when Xlint is not explicitly run. This warning occurs when a deprecated method is invoked. The following code example demonstrates such a case.

/**
* Cause -Xlint:deprecation to print warning about use of deprecated method.
*/
private static void demonstrateDeprecationWarning()
{
out.println("Fred's full name is " + fred.getName());
}

You cannot tell without the source code for the Person class (of which "fred" is an instance), but that getName() method is deprecated in Person. The following output from running javac with -Xlint, -Xlint:all, or -Xlint:deprecation confirms that (or points it out if the developer missed it).

src\dustin\examples\Main.java:47: warning: [deprecation] getName() in dustin.examples.Person has been deprecated
out.println("Fred's full name is " + fred.getName());
^

-Xlint:divzero
The divzero Xlint option indicates when integral division divides by a literal zero. A code example that will demonstrate this is shown next:

/**
* Demonstrate -Xlint:divzero in action by dividing an int by a literal zero.
*/
private static void demonstrateDivideByZeroWarning()
{
out.println("Two divided by zero is " + divideIntegerByZeroForLongQuotient(2));
}

/**
* Divide the provided divisor into the provided dividend and return the
* resulting quotient. No checks are made to ensure that divisor is not zero.
*
* @param dividend Integer to be divided.
* @return Quotient of division of dividend by literal zero.
*/
private static long divideIntegerByZeroForLongQuotient(final int dividend)
{
// Hard-coded divisor of zero will lead to warning. Had the divisor been
// passed in as a parameter with a zero value, this would not lead to
// that warning.
return dividend / 0;
}

The output from javac when the above is compiled is now shown.

src\dustin\examples\Main.java:231: warning: [divzero] division by zero
return dividend / 0;
^

When I intentionally tried to force this warning, it seemed to only work for a hard-coded (literal) zero divisor. Also, it does not flag double division because Infinity can be returned as a valid answer in that case without throwing an exception.

-Xlint:empty
The purpose of -Xlint:empty is to notify the developer that an "empty" if conditional is in the code. From my tests, this seems to only apply for the case of the empty "if" block. NetBeans provides "hints" (those yellow underlined warnings that are also marked in the right margin of the source code editor) for several types of empty statements, but -Xlint:empty seems to only flag the empty "if" statements. I included the others that NetBeans flags along with the one -Xlint:empty flags in the next source code sample.

/**
* This method demonstrates how javac's -Xlint:empty works. Note that javac's
* -Xlint:empty will only flag the empty statement involved in the "if" block,
* but does not flag the empty statements associated with the do-while loop,
* the while loop, the for loop, or the if-else. NetBeans does flag these if
* the appropriate "Hints" are turned on.
*/
private static void demonstrateEmptyWarning()
{
int[] integers = {1, 2, 3, 4, 5};
if (integers.length != 5);
out.println("Not five?");

if (integers.length == 5)
out.println("Five!");
else;
out.println("Not Five!");

do;
while (integers.length > 0);

for (int integer : integers);
out.println("Another integer found!");

int counter = 0;
while (counter < 5);

out.println("Extra semicolons.");;;;
}

The code above is filled with problematic placement of semicolons that almost certainly are not what the developer wanted. This code will compile, but the developer is warned of these suspicious situations if -Xlint, -Xlint:all, or -Xlint:empty is used with javac. The warning messages that are printed in the otherwise successful compilation are shown next.

src\dustin\examples\Main.java:197: warning: [empty] empty statement after if
if (integers.length != 5);
^

Only the empty "if" statement clause is flagged; the others are not reported by -Xlint:empty.

-Xlint:fallthrough
A tempting but controversial convenience Java provides is the ability to "fallthrough" common expressions in a switch statement to apply the same logic to multiple integral values with one piece of code. If all of the integral values with the shared functionality are empty except the final one that actually performs the functionality and provides a break, the -Xlint:fallthrough won't be activated. However, if some of the case expressions do perform their own logic in addition to the common fallthrough logic, this warning is produced. An examples that demonstrates this is shown next.

/**
* Cause -Xlint:fallthrough to print warning about use of switch/case
* fallthrough.
*/
private static void demonstrateFallthroughWarning()
{
out.print("Wilma's favorite color is ");
out.print(wilma.getFavoriteColor() + ", which is ");

// check to see if 'artistic' primary color
// NOTE: This one will not lead to -Xlint:fallthrough flagging a warning
// because no functionality is included in any of the case statements
// that don't have their own break.
switch (wilma.getFavoriteColor())
{
case BLUE:
case YELLOW:
case RED:
out.print("a primary color for artistic endeavors");
break;
case BLACK:
case BROWN:
case CORAL:
case EGGSHELL:
case GREEN:
case MAUVE:
case ORANGE:
case PINK:
case PURPLE:
case TAN:
case WHITE:
default:
out.print("NOT a primary artistic color");
}
out.print(" and is ");
// check to see if 'additive' primary color
// NOTE: This switch WILL lead to -Xlint:fallthrough emitting a warning
// because there is some functionality being performed in a case
// expression that does not have its own break statement.
switch (wilma.getFavoriteColor())
{
case BLUE:
case GREEN:
out.println("(it's not easy being green!) ");
case RED:
out.println("a primary color for additive endeavors.");
break;
case BLACK:
case BROWN:
case CORAL:
case EGGSHELL:
case MAUVE:
case ORANGE:
case PINK:
case PURPLE:
case TAN:
case YELLOW:
case WHITE:
default:
out.println("NOT a primary additive color.");
}
}

The above code example intentionally shows both cases (pun intended) of the switch/case that will and will not lead to a warning message thanks to -Xlint:fallthrough. The output, with only one warning, is shown next.

src\dustin\examples\Main.java:95: warning: [fallthrough] possible fall-through into case
case RED:
^

The case that got flagged was the RED case following the GREEN case that did some logic of its own before falling through to the RED logic.

-Xlint:finally
More than one person has warned, "Don't return in a finally clause." In fact, "Java's return doesn't always" is in The Java Hall of Shame. A Java developer can be warned about this nefarious situation by using -Xlint, -Xlint:all, or -Xlint:finally. A piece of source code demonstrating how this warning could be generated is shown next.

/**
* Demonstrate -Xlint:finally generating warning message when a {@code finally}
* block cannot end normally.
*/
private static void demonstrateFinallyWarning()
{
try
{
final double quotient = divideIntegersForDoubleQuotient(10, 0);
out.println("The quotient is " + quotient);
}
catch (RuntimeException uncheckedException)
{
out.println("Caught the exception: " + uncheckedException.toString());
}
}


/**
* Divide the provided divisor into the provided dividend and return the
* resulting quotient. No checks are made to ensure that divisor is not zero.
*
* @param dividend Integer to be divided.
* @param divisor Integer by which dividend will be divided.
* @return Quotient of division of dividend by divisor.
*/
private static double divideIntegersForDoubleQuotient(final int dividend, final int divisor)
{
double quotient = 0.0;
try
{
if (divisor == 0)
{
throw new ArithmeticException(
"Division by zero not allowed: cannot perform " + dividend + "/" + divisor);
}
// This would not have led to Xlint:divzero warning if we got here
// with a literal zero divisor because Infinity would have simply been
// returned rather than implicit throwing of ArithmeticException.
quotient = (double) dividend / divisor;
}
finally
{
return quotient;
}
}

The above is flawed and likely isn't what the developer intended. The relevant warning javac provides when Xlint is enabled is shown next.

src\dustin\examples\Main.java:159: warning: [finally] finally clause cannot complete normally
}
^

-Xlint:overrides
The -Xlint:overrides option does not replace the @Overrides annotation. The latter is an error rather than a warning anyway. Instead, -Xlint:overrides indicates when a much less obvious situation has occurred. Two Java classes are shown here to illustrate how this warning might occur. The first class is the base class and the second class extends that base class, tries to override one of the base class's methods with inclusion of an @Overrides annotation. Like all code in my examples in this post, this code does compile.

BaseClass.java
package dustin.examples;

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

/**
* Simple class intended to help demonstrate -Xlint:overrides by providing a
* method that won't be overridden quite the same by its child.
*/
public class BaseClass
{
protected List<String> names = new ArrayList<String>();

public BaseClass() {}

public void addNames(final String[] newNames)
{
for (final String name : newNames)
{
names.add(name);
}
}
}

ChildClass.java
package dustin.examples;

/**
* Simple class intended to help demonstrate -Xlint:overrides by "sort of"
* overriding a method defined in its parent.
*/
public class ChildClass extends BaseClass
{
@Override
public void addNames(final String... newNames)
{
for (final String name : newNames)
{
this.names.add(name);
}
}
}

Here is the warning javac provides when the appropriate -Xlint flag is used.

src\dustin\examples\ChildClass.java:10: warning: addNames(java.lang.String...) in dustin.examples.ChildClass overrides addNames(java.lang.String[]) in dustin.examples.BaseClass; overridden method has no '...'
public void addNames(final String... newNames)
^

-Xlint:path
The -Xlint:path is one of my favorites. I like it so much, in fact, that I have blogged on it specifically. As I stated in that post, this is particularly handy in identifying assumed classpath locations that don't really exist. This knowledge can help in all kinds of class loader issues. The option is not limited to classpaths, but that is where I use it most.

There are a couple interesting notes about this particular option. First, this was one I was unable to generate when building with Ant because Ant automatically detects non-existent paths as well and doesn't apply them (therefore not giving -Xlint:path a chance to be the hero).

The type of Ant declaration I often use when compiling my Java code is shown next. It specifies -Xlint for all javac warnings in the compilerarg element nested with the javac element.

<target name="compile"
description="Compile the Java code."
depends="-init">
<javac srcdir="${src.dir}"
destdir="${classes.dir}"
classpathref="classpath"
debug="${javac.debug}"
includeantruntime="false">
<compilerarg value="-Xlint"/>
</javac>
</target>

When I build my sample application using Ant and the target shown above, I do not see the path-oriented warning. If I turn up the verbosity during the Ant build, I can detect why when it reports this message: "dropping C:\noSuchDirectory from path as it doesn't exist"

When I build my final example with javac on the command line, there are 13 warnings covering the ten Xlint categories displayed. When I build it using Ant and the target above, there are only 12 warnings displayed and all but the -Xlint:path warning are listed. Here is what the output from -Xlint:path does look like when javac is run from the command line:

warning: [path] bad path element "C:\noSuchDirectory": no such file or directory

The second interesting observation about -Xlint:path is that it's not a source code warning like the others covered here, but is instead more a warning about how javac itself is being applied to the source code. Given that, there's no source code to see here. Let's move on.

-Xlint:serial
Josh Bloch, in Effective Java, discusses the importance of generating a serialVersionUID for classes that are marked as Serializable. Indeed, the Javadoc for Serializable also cover the importance of this. The -Xlint:serial flag will warn a developer when a Serializable class does not have an explicit serialVersionUID. It's time to look at the previously mentioned Person class (discussed in conjunction with -Xlint:deprecation), which is Serializable, but does not have an explicit serialVersionUID declared.

package dustin.examples;

import java.io.Serializable;

/**
* Person class that intentionally has problems that will be flagged as warnings
* by javac with -X non-standard options.
*/
public final class Person implements Serializable
{
// no serialVersionUID should demonstrate -Xlint:serial

private final String lastName;

private final String firstName;

private final Gender gender;

private final Color favoriteColor;

public Person(
final String newLastName,
final String newFirstName,
final Gender newGender,
final Color newFavoriteColor)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.gender = newGender;
this.favoriteColor = newFavoriteColor;
}

public String getLastName()
{
return this.lastName;
}

public String getFirstName()
{
return this.firstName;
}

public String getFullName()
{
return this.firstName + " " + this.lastName;
}

/**
* Provide the person's full name.
*
* @return Full name of this person.
* @deprecated Use getFullName() instead.
*/
@Deprecated
public String getName()
{
return this.firstName + " " + this.lastName;
}

public Gender getGender()
{
return this.gender;
}

public Color getFavoriteColor()
{
return this.favoriteColor;
}


/**
* NetBeans-generated equals(Object) method checks for equality of provided
* object to me.
*
* @param obj Object to be compared to me for equality.
* @return {@code true} if the provided object and I are considered equal.
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Person other = (Person) obj;
if ((this.lastName == null) ? (other.lastName != null) : !this.lastName.equals(other.lastName))
{
return false;
}
if ((this.firstName == null) ? (other.firstName != null) : !this.firstName.equals(other.firstName))
{
return false;
}
if (this.gender != other.gender)
{
return false;
}
if (this.favoriteColor != other.favoriteColor)
{
return false;
}
return true;
}


/**
* NetBeans-generated hashCode() method.
*
* @return Hash code for this instance.
*/
@Override
public int hashCode()
{
int hash = 7;
hash = 59 * hash + (this.lastName != null ? this.lastName.hashCode() : 0);
hash = 59 * hash + (this.firstName != null ? this.firstName.hashCode() : 0);
hash = 59 * hash + (this.gender != null ? this.gender.hashCode() : 0);
hash = 59 * hash + (this.favoriteColor != null ? this.favoriteColor.hashCode() : 0);
return hash;
}


@Override
public String toString()
{
return getFullName();
}
}

Here is what javac tells me about this when I have -Xlint, -Xlint:all, or -Xlint:serial specified.

src\dustin\examples\Person.java:9: warning: [serial] serializable class dustin.examples.Person has no definition of serialVersionUID
public final class Person implements Serializable
^

-Xlint:unchecked
We've finally arrived at the tenth -Xlint option. This one is covered last because "U" falls so late in the English alphabet, but it's arguably appropriate to cover it last anyway because it's one of the ones most Java developers probably see most often. This -Xlint:unchecked and the previously covered -Xlint:deprecation are the only two of the ten covered here that are warned about even when -Xlint is explicitly stated to warn about "none." Because it's so common, there are numerous code samples that demonstrate it. One simple one is shown here.


/**
* Demonstrate the commonly seen -Xlint:unchecked in action.
*
* @return Set of Person objects.
*/
private static Set demonstrateUncheckedWarning()
{
final Set people = new HashSet();
people.add(fred);
people.add(wilma);
people.add(barney);
return people;
}

I could have declared the Set interface and its HashSet implementation above to be specifically of type Person, but I failed to do so. This leads to four warnings as shown next.


src\dustin\examples\Main.java:243: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.Set
people.add(fred);
^
src\dustin\examples\Main.java:244: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.Set
people.add(wilma);
^
src\dustin\examples\Main.java:245: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.Set
people.add(barney);
^
src\dustin\examples\Main.java:246: warning: [unchecked] unchecked conversion
found : java.util.Set
required: java.util.Set
return people;
^

The numerous warnings here are how my example got 13 total warnings for ten Xlint categories.

Other Noteworthy Items
This post is already pretty long, so I'm only going to briefly mention a last few items of interest. First, not only can one go without using -Xlint at all when using javac or use -Xlint:none to explicitly not use -Xlint, but one has even more granular control on what is not printed. This is available by using a minus sign (-) in front of a particular Xlint option to specify not to warn about it. For example, a developer who doesn't care about not having a serialVersionUID could specify -Xlint:-serial to explicitly tell the javac compiler to not warn about absence of a serialVersionUID in a Serializable class.

Another way to limit the printing of these Xlint-based warnings is (at least in some cases) the availability of the @SuppressWarnings annotation to state which warnings should be ignored. These annotations are placed directly in the source code, but will keep Xlint from reporting the warning. Casper Bang provides nice coverage of the use of this annotation in his post @SuppressWarnings values. Alex Miller has provided a nice summary of @SuppressWarnings options as well.

I mentioned briefly that NetBeans covers several more "empty" conditions than does -Xlint. This tends to be true of many other warnings as well. NetBeans and the other major Java IDEs tend to warn about more types of suspicious behavior than does -Xlint.

The Rest of the Code
I already included the complete source code for three classes above (Person.java, BaseClass.java, and ChildClass.java). Here I include source code for the Main.java that had many of the examples that led to Xlint complaining along with the source code for the two simple enums Gender and Color.

Gender.java
package dustin.examples;

/**
* Gender.
*/
public enum Gender
{
FEMALE,
MALE
}

Color.java
package dustin.examples;

/**
* Simple Color representation.
*/
public enum Color
{
BLACK,
BLUE,
BROWN,
CORAL,
EGGSHELL,
GREEN,
MAUVE,
ORANGE,
PINK,
PURPLE,
RED,
TAN,
WHITE,
YELLOW
}

Main.java
package dustin.examples;

import java.util.Set;
import java.util.HashSet;
import static java.lang.System.out;

/**
* Main executable demonstrating HotSpot's non-standard Xlint warning flags.
*/
public class Main
{
/** Fred. */
private final static Person fred =
new Person("Flintstone", "Fred", Gender.MALE, Color.ORANGE);

/** Wilma. */
private final static Person wilma =
new Person("Flintstone", "Wilma", Gender.FEMALE, Color.PURPLE);

/** Barney. */
private final static Person barney =
new Person("Rubble", "Barney", Gender.MALE, Color.BROWN);


/**
* Demonstrates -Xlint:cast warning of a redundant cast.
*/
private static void demonstrateCastWarning()
{
final Set<Person> people = new HashSet<Person>();
people.add(fred);
people.add(wilma);
people.add(barney);
for (final Person person : people)
{
// Redundant cast because generic type explicitly is Person
out.println("Person: " + ((Person) person).getFullName());
}
}


/**
* Cause -Xlint:deprecation to print warning about use of deprecated method.
*/
private static void demonstrateDeprecationWarning()
{
out.println("Fred's full name is " + fred.getName());
}


/**
* Cause -Xlint:fallthrough to print warning about use of switch/case
* fallthrough.
*/
private static void demonstrateFallthroughWarning()
{
out.print("Wilma's favorite color is ");
out.print(wilma.getFavoriteColor() + ", which is ");

// check to see if 'artistic' primary color
// NOTE: This one will not lead to -Xlint:fallthrough flagging a warning
// because no functionality is included in any of the case statements
// that don't have their own break.
switch (wilma.getFavoriteColor())
{
case BLUE:
case YELLOW:
case RED:
out.print("a primary color for artistic endeavors");
break;
case BLACK:
case BROWN:
case CORAL:
case EGGSHELL:
case GREEN:
case MAUVE:
case ORANGE:
case PINK:
case PURPLE:
case TAN:
case WHITE:
default:
out.print("NOT a primary artistic color");
}
out.print(" and is ");
// check to see if 'additive' primary color
// NOTE: This switch WILL lead to -Xlint:fallthrough emitting a warning
// because there is some functionality being performed in a case
// expression that does not have its own break statement.
switch (wilma.getFavoriteColor())
{
case BLUE:
case GREEN:
out.println("(it's not easy being green!) ");
case RED:
out.println("a primary color for additive endeavors.");
break;
case BLACK:
case BROWN:
case CORAL:
case EGGSHELL:
case MAUVE:
case ORANGE:
case PINK:
case PURPLE:
case TAN:
case YELLOW:
case WHITE:
default:
out.println("NOT a primary additive color.");
}
}


/**
* Demonstrate -Xlint:finally generating warning message when a {@code finally}
* block cannot end normally.
*/
private static void demonstrateFinallyWarning()
{
try
{
final double quotient = divideIntegersForDoubleQuotient(10, 0);
out.println("The quotient is " + quotient);
}
catch (RuntimeException uncheckedException)
{
out.println("Caught the exception: " + uncheckedException.toString());
}
}


/**
* Divide the provided divisor into the provided dividend and return the
* resulting quotient. No checks are made to ensure that divisor is not zero.
*
* @param dividend Integer to be divided.
* @param divisor Integer by which dividend will be divided.
* @return Quotient of division of dividend by divisor.
*/
private static double divideIntegersForDoubleQuotient(final int dividend, final int divisor)
{
double quotient = 0.0;
try
{
if (divisor == 0)
{
throw new ArithmeticException(
"Division by zero not allowed: cannot perform " + dividend + "/" + divisor);
}
// This would not have led to Xlint:divzero warning if we got here
// with a literal zero divisor because Infinity would have simply been
// returned rather than implicit throwing of ArithmeticException.
quotient = (double) dividend / divisor;
}
finally
{
return quotient;
}
}


/**
* Demonstrate -Xlint:divzero in action by dividing an int by a literal zero.
*/
private static void demonstrateDivideByZeroWarning()
{
out.println("Two divided by zero is " + divideIntegerByZeroForLongQuotient(2));
}


/**
* Surprisingly, there is no -Xlint warning option for this highly
* suspicious situation of passing an object to a Set.contains call that
* could not possibly hold that type of object (could never result to true).
*/
private static void demonstrateNoContainsWarning()
{
final Set<Person> people = new HashSet<Person>();
if (people.contains("Dustin"))
{
out.println("Here's there!");
}
}


/**
* This method demonstrates how javac's -Xlint:empty works. Note that javac's
* -Xlint:empty will only flag the empty statement involved in the "if" block,
* but does not flag the empty statements associated with the do-while loop,
* the while loop, the for loop, or the if-else. NetBeans does flag these if
* the appropriate "Hints" are turned on.
*/
private static void demonstrateEmptyWarning()
{
int[] integers = {1, 2, 3, 4, 5};
if (integers.length != 5);
out.println("Not five?");

if (integers.length == 5)
out.println("Five!");
else;
out.println("Not Five!");

do;
while (integers.length > 0);

for (int integer : integers);
out.println("Another integer found!");

int counter = 0;
while (counter < 5);

out.println("Extra semicolons.");;;;
}


/**
* Divide the provided divisor into the provided dividend and return the
* resulting quotient. No checks are made to ensure that divisor is not zero.
*
* @param dividend Integer to be divided.
* @return Quotient of division of dividend by literal zero.
*/
private static long divideIntegerByZeroForLongQuotient(final int dividend)
{
// Hard-coded divisor of zero will lead to warning. Had the divisor been
// passed in as a parameter with a zero value, this would not lead to
// that warning.
return dividend / 0;
}


/**
* Demonstrate the commonly seen -Xlint:unchecked in action.
*
* @return Set of Person objects.
*/
private static Set<Person> demonstrateUncheckedWarning()
{
final Set people = new HashSet();
people.add(fred);
people.add(wilma);
people.add(barney);
return people;
}


/**
* Main executable function to demonstrate -Xlint. Various -Xlint options
* are demonstrated as follows:
* <ul>
* <li>{@code -Xlint:cast}</li>: This class's method demonstrateCastWarning()
* demonstrates how a redundant cast can lead to this warning.</li>
* <li>{@code -Xlint:deprecation}: This class's method demonstrateDeprecationWarning()
* intentionally invokes a deprecated method in the Person class.</li>
* <li>{@code -Xlint:divzero}: This class's demonstrateDivideByZeroWarning()
* method demonstrates this warning generated when a literal zero is
* used as a divisor in integer division.</li>
* <li>{@code -Xlint:empty}: This class's demonstateEmptyWarning() method
* demonstrates that (likely accidental) "if" expression without any
* result of the condition being {@code true} being performed results in
* a warning this option's set.
* <li>{@code -Xlint:fallthrough}: This class's method demonstrateFallthroughWarning()
* demonstrates how {@code switch} statements with {@code case} expressions
* without their own {@code break} statements may or may not lead to
* this producing a warning message.</li>
* <li>{@code -Xlint:finally}: This class's method demonstrateFinallyWarning()
* demonstrates the warning related to a return from a {@code finally}
* clause.</li>
* <li>{@code -Xlint:overrides}: This is demonstrated in classes external to
* this one: {@code BaseClass} and its child class @{code ChildClass}.</li>
* <li>{@code -Xlint:path}: This is shown by providing a path to the javac
* compiler's classpath option for a location that does not exist.</li>
* <li>{@code -Xlint:serial}: The Person class implements the Serializable
* interface, but does not declare an explicit serialVersionUID.</li>
* <li>{@code -Xlint:unchecked}: This class's demonstrateUncheckedWarning()
* demonstrates this warning message.</li>
* </ul>
*
* @param arguments Command-line arguments: none expected.
*/
public static void main(final String[] arguments)
{
demonstrateCastWarning();
demonstrateDeprecationWarning();
demonstrateDivideByZeroWarning();
demonstrateEmptyWarning();
demonstrateFallthroughWarning();
demonstrateFinallyWarning();
demonstrateUncheckedWarning();
}
}

Conclusion

David Walend's post Amazing -Xlint points out that Xlint "made short work of the clean-up pass" and "pointed out places that needed some more thought, and helped keep me honest." I have found Xlint to be useful at time for similar reasons. The IDEs often provide me with warnings that cover the same ones as Xlint (and often many more), but there are times when things slip through and Xlint is there to capture them. These are not always deal-breaker issues, but sometimes they are and sometimes they have the potential to be.

Thứ Hai, 27 tháng 9, 2010

JavaOne 2010: General Observations and Overall Impressions

JavaOne 2010 is over. Some questions have been answered, many in the way that I hoped they would be. Overall, it was a great conference. Here are some of my thoughts regarding JavaOne 2010.

JavaOne's Relationship to Oracle OpenWorld
Although I don't know how the 41,000 attendees break down (especially because some attendees attend portions of both conferences), my guess is that attendees who would say they are primarily attending Oracle OpenWorld probably outnumber attendees who would say they are primarily attending JavaOne by 3 to 1. I believe that Oracle OpenWorld has been larger than JavaOne just about every year in which they've both existed and I believe the difference has been even more significant in recent years.

Some have complained about JavaOne not being treated as significantly as Oracle OpenWorld.  Evidence they can cite includes Oracle OpenWorld getting the Moscone Center and an Oracle OpenWorld keynote kicking off the week (other than MySQL Sunday and a few other activities earlier on Sunday). As far as the Moscone Center goes, logic dictates that the conference with larger number of attendees should be held there. I generally enjoyed the opportunity to walk outside as I went back and forth between the Hilton and Parc 55. I do agree that it required more time than I would have liked to get down to the Moscone Center, but I only needed to do that two or three times.

I thought Oracle did a nice job of giving JavaOne its own conference feel in the Union Square area. The Mason Street Tent had great proximity to the Hilton and Parc 55. The Hilton Grand Ballroom was spacious enough to hold the majority of the JavaOne attendees (with overflow generally being in the Yosemite conference rooms).

There's no question that Oracle OpenWorld is the "big brother" compared to the smaller JavaOne. However, I personally felt that JavaOne Opening Keynote was more interesting than the Oracle OpenWorld keynote. Instead of focusing on the relative aspects of Oracle OpenWorld versus JavaOne, however, I prefer to focus solely on my experience with JavaOne 2010 regardless of how Oracle OpenWorld plays into it.


There are likely significant financial and logistical advantages for Oracle to holding the conferences all at once. If there are, I can live with JavaOne as it was held. However, if Oracle is only holding them together in an attempt to allow attendees to attend all the conferences, I think that's an advantage that only a small minority of the attendees take support of. My guess is that most JavaOne attendees would give up the opportunity to attend Oracle OpenWorld if they could have JavaOne in the Moscone Center.


Common Themes
One of the things I look for in a conference is common themes that pervade the conference. These generally give me an idea of which products, libraries, frameworks, and technologies are most worth further investigation. Some of the things that stood out for their commonality in this edition of JavaOne 2010 were utility of Groovy (one I already had bought into), enthusiasm for Scala, the wealth of available unit testing products (Hamcrest), future of Java, and, or course, the future of JavaFX.

Groovy is In

It seems to me that Groovy has either reached or is very close to reaching that point where it is no longer new or unusual to the majority of conference attendees. Groovy, it seems, is poised to soon join the list of Java-related tools that are "taken for granted." This is a good thing because it indicates wide and general acceptance and it means less introductory sessions on the subject and more advanced sessions and more sessions that just use Groovy as a matter of course in presenting something else. It reminds me that we used to have introductory XML presentations, introductory Swing presentations, and so forth. We rarely see those today as those are assumed technologies and I believe Groovy is taking its first steps into that direction. It was cited heavily in presentations on unit testing, for example. My belief is that Groovy is becoming more like Ant in terms of familiarity: whether Java developers like or don't like Groovy, most will likely have at least passing familiarity with it in the future because of its prevalence in tools, frameworks, and presentations.

Scala May be the Next Big Thing

Scala seems to be taking Groovy's place in the list of JVM languages that may be the "next big thing" (Groovy, as I stated in the previous paragraph, seems to have arrived at "the latest big thing"). Scala has some zealous evangelists with some features to back up that enthusiasm.

Polyglot Programming

As my discussion of themes related to Groovy and Scala implies, polyglot programming was a major theme at this conference.  However, it went beyond programming. There was discussion of polyglot persistence and other areas of software development where the developer benefits from knowing and using multiple alternatives at the same time.

JavaFX Has a Future

As it has for every edition of JavaOne since 2007 JavaOne, JavaFX again was the overall dominant theme of this conference. I felt that this year was different, however, in that this year's marketing for JavaFX actually seems to be pointed in a positive direction that bodes well for a long-term future for the technology if the bold plans are realized. The plan to scrap JavaFX Script and make Java APIs available for accessing JavaFX seems obvious but bold at the same time. My only surprise is that this decision (to make JavaFX available via normal Jav APIs) was not made and announced sooner.

Several Java developers told me they could not use Flex because it's not Java. I always asked, "Is JavaFX?" It was difficult to find any measure by which JavaFX has been Java other than the first four letters in its name and the ability to run on the JVM (which a host of other languages can do as well). Although I think the latest news on JavaFX is very positive, it still needs to be implemented. Also, there are still many questions. Will JavaFX itself be part of the SDK? Will JavaFX be fully licensed the same as the SDK? Or, will JavaFX be more like Google Web Toolkit, Spring, or a host of other frameworks that play nicely with standard Java but are not themselves standard Java. The updated JavaFX Roadmap does a good job of covering features in "JavaFX 2.0," but I didn't see anything covering the licensing issues.

I think the success of the various non-standard Java libraries and frameworks show that these can succeed without being part of "standard Java" and without being JCP/JSR-based. My best current guess is that JavaFX will be delivered like these third-party products and won't be included in Java SE or Java EE. Still, I expect it to see a major upswing in adoption once developers are free to invoke JavaFX from Java, Groovy, Scala, or any other JVM-based language.

The JavaFX announcement has interesting implications related to the theme of polyglot programming mentioned earlier. On the one hand, scrapping a single non-Java language in JavaFX Script in favor of any JVM language favors polyglot programming. On the other hand, the resistance to using JavaFX Script can be interpreted as an indication that there are still many in our community not willing to learn an entirely new language to use JavaFX. One downside to the approach of requiring JavaFX Script to use JavaFX was that a developer (rightfully) could ask himself or herself, "Why learn an entirely new language just to use the newer, less mature JavaFX if I can use the more mature Flex framework by similarly learning a new language?"

Future of Java

The future of Java was also (not surprisingly) a major theme at JavaOne 2010. In general, I thought it the discussions regarding the future of Java were more positive than negative. I especially liked the implication of making Java more developer-friendly while retaining its current power. I thought I head the slightest hint from Mark Reinhold that there has even been discussion of more significant changes in later versions of Java (after Java 8) such support for generics reification. Major changes like those could mean good things for Java. Sun never had any inclination for breaking backwards compatibility; perhaps Oracle is more willing to consider it.

Reinhold also stated that they expect to have major releases more frequently than the five year time span between Java SE 6 and Java 7's likely release. It was also nice to have it confirmed that the JDK 7/JDK 8 Plan B is the currently chosen plan for the next releases of Java.

One twist on the future of Java is the issue of the next big JVM language. Stephen Colebourne presented on this in his The Next Big JVM Language presentation. Although I was unable to attend the presentation, I thought his personal conclusion from preparing this presentation was interesting: "my conclusion is that the language best placed to be the Next Big JVM Language is Java itself." Cay Horstmann has addressed this observation in his similarly titled post The Next Big JVM Language. In that post, Horstmann states that he doesn't think Java itself will be the next big language. He then looks at how Scala fits or doesn't fit that potential.

San Francisco
This was my first time to spend significant time in San Francisco. I really enjoyed the city. One of the things that I liked about JavaOne's location was the proximity to the thriving Union Square area of San Francisco.  I stayed at the Warwick San Francisco and truly enjoyed the experience. Just about everyone I met from the area (taxicab drivers, hotel staff, restaurant staff, etc.) were extremely friendly and appreciated the business that the conferences brought to the city. Tourism is San Francisco's #1 industry and I can appreciate why.

Just about every merchant, taxicab driver, and other vendor I talked to in San Francisco was aware of "the Oracle conference." Even when I was riding one of those double-decker tourist buses that lets you hop on and off as they stop at various locations in the city, the tour guide mentioned the Oracle conference and specifically called out the Appreciation Event (she called it, not inappropriately, "the Oracle party"). She observed, "It sure doesn't seem like there is a recession."

This was a great time of year to be in San Francisco. The mornings and evenings were cool and the afternoons were warm. The weather was so clear that I could see the San Francisco Bay, the Golden Gate Bridge, and the Bay Bridge any day that I was down in that area.


The Conference Sessions
The conference sessions were excellent. This is one of the few conferences I have attended where I did not regret attending any of the sessions that I did attend. I blogged on each one of them on this blog. I really liked the separation of marketing from technical sessions. This reminded me of my favorite aspect of conferences such as the Colorado Software Summit that always kept things technical. Peter Pilgrim blogged on some of the technical sessions and many attendees blogged on individual presentations they attended or presented. My own list of JavaOne 2010 presentation summaries/reviews is shown here.

Summaries and Highlights
There have been several excellent blogs posts and articles summarizing JavaOne 2010. I have collected links to a few here.

JavaOne 2010 Overall
JavaOne 2010 General Technical Session
JavaOne 2010 Opening Keynote
Mobile Technology
Mobile technology was in high use at this conference. I found my Droid to be very useful for many things during the conference. It allowed me to use its GPS to find my way around San Francisco. It also helped me to look up my Schedule Builder as needed. It was also useful for learning of sessions changes and filling out session surveys in between sessions. I used it to look up different terms via Google and Wikipedia as well. Finally, I used it to mail myself notes from some sessions when my laptop battery was nearly dead. There were mobile devices all over the place and the one drawback was the subset of individuals who chose to try to read their mobile devices while walking. The halls could get crowded at times with people heading in different directions and it didn't help to have a person wandering aimlessly and without obvious direction because he or she was too consumed with his or her mobile device.

I also was happy to have my Verizon Prepaid Mobile Broadband. It was more cost efficient to use this than to pay the hotel's daily wireless access fee (similar to how it was more cost efficient to use taxicabs than to pay to park a rental vehicle at the hotel). Although the conference's provided broadband was generally sufficient, I experienced problems with it during the "big" sessions like the JavaOne Opening Keynote and JavaOne General Technical Session. It was nice in those relatively rare events to still have access to the Internet for looking up terms and posting my blog.

Conclusion
It's my belief that JavaOne 2010 will be remembered more for being the first under Oracle stewardship, for being held outside of the Moscone Center, and for the announcements related to the future of Java and JavaFX than it will be remembered as a Googless JavaOne. To be sure, it would have been nice to have Google's employee's presentations given or, at the very least, to have had additional presentations given in those slots. But, even as it was, there were plenty of good presentations and excitement about the new directions announced for the language and platform.

Thứ Năm, 23 tháng 9, 2010

JavaOne 2010: Concurrency Grab Bag

The final session that I attended at JavaOne 2010 was the presentation "Concurrency Grab Bag: : More Gotchas, Tips, and Patterns for Practical Concurrency" by Sangjin Lee and Debashis Saha (not here today) of eBay. Despite what my schedule stated on Schedule Builder, this second instance of this session was held in Parc 55's Marketstreet rather than in Cyril Magnin II.

Lee stated that many of the concurrency problems he sees involve use of Java collections. He said this presentation is on practical issues the audience would be likely to see. He referenced a session from last year's JavaOne (Robust and Scalable Concurrent Programming: Lessons from the Trenches) and said this year's presentation starts from there and delves a little deeper into the patterns.

Lee said it is better to have correctness first and then achieve performance and scalability next. Because problems usually repeat themselves, anti-patterns serve as "crutches" (red flags) for spotting "bad smell."

Lee showed an example where a concurrency issue arose because of the use of lazy initialization. He stated that we often don't need to load these lazily. He showed how to address this with the use of the volatile keyword in situations when the "data is optional and large." Lee mentioned that use of volatile is "not zero cost," but is typically not expensive enough to worry about.

One observation Lee made was that we often have read-heavy functionality with few writers or write-heavy functionality with few readers. He outlined several implementation choices for the case of "many readers, few writers." I really liked his table summarizing "many readers, fewer writers" with type, concurrency, and staleness behavior column headers. I'd like to get a copy of the slides to use that table as a reference.

Lee also stated that the described copy-on-write approach is less useful for Maps because ConcurrentHashMap works well (albeit at the cost of large memory usage). If read performance is desired enough to justify the cost to writes, copy-in-write is great. However, Lee had some caveats for use of copy-on-write: significant write performance degradation, must avoid direct access to underlying reference, and issues of staleness. In short, what I took away from this section is that, for the case of many reads and few writes, synchronize can be used in the simplest/smallest cases, the concurrent collections will support most general cases best, and copy-on-write might be best when certain conditions exist (no applicable concurrent collection, for example).

Lee was unable to spend as much time on the case of many writers with few readers, but he did cite logging as a use case here. He pointed out that in this case, use of synchronize worsens hotly contested writes. ConcurrentHashMap is generally best again, but he also covered the Asynchronous background processor.

Lee reminded us of advice that is commonly given at these types of sessions: don't tune unless necessary. He also recommended the Highly Scalable Java project rather than rolling custom implementations for highly concurrent applications.

[UPDATE (24 September 2010)] As Sangjin states in the first comment on this post, he has made his slides available for reference at http://www.slideshare.net/sjlee0/concurrency-grab-bag-javaone-2010/download. He also states that he has been told that his slides and the recording of his presentation are accessible versus Schedule Builder. These are well worth checking out.

This presentation was recorded and so may be available online in the near future. The audience was obviously very interested in the subject because we had a packed room of individuals who came to the final session of the conference to see it. You could also see the enthusiasm in the number of questions asked during the presentation. The downside of these questions was that it forced Lee to be rushed at the end. Lee did a nice job, however, in repeating the questions and statements so that everyone could hear what was said and this should benefit the recorded version as well.

I'd really like to get my hands on these slides. They were difficult at times to see because of the red font on blue background. Turning off the front lights helped tremendously, but it was still difficult to see the bottom of the screen from the back. This is a general criticism I have of the venue. Most of the screens in these hotel conference rooms were situated such that the bottom quarter of the screens were difficult to see from past the first several rows.

I really liked how Lee (and many other) put code samples in the slides because I have found as a presenter and as an attendee that it's easier to follow code and how it relates to discussion when it's in the slides than when it's in the IDE. Besides that, having the code in the slides keeps it packaged with the slides. I'd like to get a copy of Lee's slides because of the good reference information in them and because of the code samples I'd like to take a closer look at.

JavaOne 2010: A Brief Introduction to Scala

Steven Reynolds (a "software developer and manager" who works at INT) presented "A Brief Introduction to Scala" at JavaOne 2010. [As a side note, JavaFX Script is a casualty announced at JavaOne 2010, but JavaFX's use of SceneGraph seems stronger than ever and Reynolds has a presentation on that.] Reynolds asked who had heard of Scala and nearly everyone in the near-capacity room raised their hand.  However, when he followed up with who actually uses Scala, I could count the number of raised hands on the fingers of one of my hands.

Reynolds described Scala as "new-ish programming language for the JVM" that features a static type system and support for functional programming. In answering his own question in a slide titled, "Why Does Functional Programming Matter?" Reynolds (with tongue firmly in cheek) showed a direct correlation between Functional Programming and Google's $150 billion worth (MapReduce is the connection).

Scala's design goals include combining functional programming with object-oriented programming. Scala is also designed to be practical and interoperable with Java. The ability to call from Java to Scala and from Scala to Java allows Scala access to all SDK and other Java libraries. Scala designed to be powerful language that "trusts the programmer" and has a "powerful static type system that's easy to use." Reynold is "mystified" by people referring to Scala as a scripting language because of its powerful static typing. Frankly, I too think more of a dynamic language like Groovy for scripting than I do a static language like Java or Scala.

Reynolds provided a brief overview of characteristics of functional programming. In functional programming, functions are first class citizens. Functional programming has extreme immutability. Scala, because it's a "blended" language, does support mutability. The advantages of functional programming is that "what was once true is always true." In addition, "reasoning and testing are simpler." Reynolds also stated that Scala is "nice for concurrency and distributed systems." Reynolds' listed disadvantages of Scala were that "modular programming is sometimes harder" and there are "sometimes performance issues." Reynolds explained that these performance issues are sometimes attributable to the need to copy objects for immutability support.

Renyolds recommends the book Structure and Interpretation of Computer Programs. He stated, however, that you need to know Scheme to read this book.

Scala "gently guides you to use immutable code," but does support mutability. Reynolds talked about the difference between the Scala keywords val and var (val is for "unchanging value" and "var" is for "varying/variable value") when designating variables.

In Scala, every statement has a value. Reynolds contrasted this to Java where, for example, "if" statements don't really have values. Scala supports type referencing similar to Groovy's. I thought it was helpful to see the chart with a picture of a subset of Scala's type system. This visually made it clear that the Scala String and Double are not the same as equivalently named types in Java. It is interesting that the integer type in Scala is Int (capitalized like the Java reference type Integer, but with the same letters as the primitive 'int' type). Reynolds emphasized that the Scala types are more fully interconnected with each other in a lattice than are Java types (primitives are off on their own).

Reynolds showed an example from Scala's Predef that is available anywhere in Scala. He also talked about Scala's handy tuples. Reynolds's example created a tuple with simple parentheses-based syntax.

C++ supports multiple implementation inheritance (which is well known for the diamond problem) and Java intentionally only has single implementation inheritance. Scala goes in between: it is object-oriented with inheritance and objects and has single implementation inheritance with mixins (Traits).Scala's "with" keyword allows specification of the mixin/Trait.

Reynolds described how Scala-specific features like Traits can work when Scala is compiled to Java byte code. Scala compiles to .class files and be placed into a JAR just as in Java. Then, Reynolds suggested, use an IDE to open that JAR in a new project. He showed this with NetBeans 6.9. This gave insight into what this looks like "in a pure Java sense." Although Reynolds called it "under the hood and low level," I do like to use tactics like this to better understand "the magic." Reynolds also used Eclipse to see the byte code of this Scala-based JAR.

The Scala compiler (scalac) compiles Scala code into Java bytecode. Another good tip Reynolds provided is to use the scalac -Xprint:typer option to see what is generated. For someone with some Java experience and thinking about using Scala, these kinds of ideas (using the IDE to see Java equivalent or using the -Xprint:typer option with scalac) can help increase the comfort level in first using Scala.

Reynolds showed Scala's highly flexible case statement and I found it interesting that underscore (_) represents default case. It appears to me that, like Groovy, Scala's case needs to be carefully used because multiple options could "match" the condition (order does matter!).

Reynolds introduced Scala's well-known Actors and talked about how they help avoid shared mutable state. Messages are sent asynchronously. Reynolds briefly summarized inversion of control and stated that Scala had a design goal with Actors to enable event programming without inversion of control. This led to his explanation that react does not return. Benefits of Actors include no need to worry about "safe publication" and availability of explicit concurrency. Reynolds stated that even this nice approach to concurrency is not perfect.

I enjoyed Reynolds's presentation. It was exactly what I was looking for in an initial Scala overview. My only complaint was that this packed room got pretty warm in the afternoon. I normally don't have a lot of patience for that, but Reynolds's presentation was good enough to keep me there despite the uncomfortable temperature.

During the question and answer section, an attendee asked if JUnit could be used with Scala. Reynolds confirmed that JUnit can be used with Scala and referenced other Scala-specific testing framework ScalaTest as well. Another attendee asked about tooling for Scala. Reynolds acknowledged that Scala tooling has room for improvement. He stated that Scala is expected to have built-in features added that will help tooling for Scala.

Scala seems to be all the rage at this year's JavaOne. I appreciated Reynolds acknowledging that Scala might actually have a weakness or two. In Andres Almiray's presentation yesterday, he made an interesting comment during the question and answer section in which he sort of summarized on-the-fly that Scala may not be as strong as competitors in some areas (such as Groovy in metaprogramming or Clojure in concurrency), but that Scala does many things very well. If one is looking for a "general" language to cover broad needs, that's the kind of description you'd want.

Scala seems to be one of those things which has enthusiastic evangelists running around telling everyone how great it is without admitting many or significant drawbacks. I'm always leery of such one-sided things: they rarely (read never) are as flawless as advertised. However, I think Scala could be like Ruby was for me: it cannot possibly live up to the uber hype, but it really is nice when you get past the hype and look at it realistically. I try to not let unabated enthusiasm from well-meaning supporters distract me from rather a technology is useful to learn or not. I looked past this with Ruby and liked what I found and I could see the same happening for Scala. One of the types of sessions I like to attend at a conference are those that, within an hour or so, can help me decide if a particular subject is worth further investigation. This session did that for me: I saw enough here to believe that Scala may be worth some time investment.