Java programming techniques
switch on String enum
In circumstance such as parsing of text, one often wants multiple
control paths based on the value of a string token. Many languages
have special syntax for this purpose. Java 5 provides in its
enum
and switch
a convenient means to achieve this,
although the technique is not obvious.
Java switch
cases must be compile-time constants:
enum
is ideal for this. However, the switch
is
type-safe, and so must take an enum
object of the same type
as its case
statements. How does one convert a String to an
enum
?
A constructor will not work. An enum
constructor is special in
that it is called automatically at initialization to construct the
enum
object, but cannot be called directly in code. Java
enum
s cannot be instantiated.
But we need to convert a String to an enum
at run time.
The trick is the Enum.valueOf()
method, which returns the
name of the enum
constant as a String.
Another concern is that in converting a String to an enum
,
valueOf()
throws an exception if the String isn’t exactly one of the
enum
s.
public class SwitchEnumString { enum Beatle { John, Paul, George, Ringo, none; // Here, the choice was to catch the exception at a low level, // and return a 'none' enum. But there are other ways. static Beatle fromString( String str ) { try { return Beatle.valueOf( str ); } catch( Exception e ) { return none; } } } public static void main( String[] args ) { if( args.length == 0 ) System.err.println( "Usage:\n" + "\tSwitchEnumString <list of first names of Beatles>" ); for( String firstName : args ) System.out.println( getLastName( firstName ) ); } static String getLastName( String first ) { switch( Beatle.fromString( first ) ) { case John: return "Lennon"; case Paul: return "McCartney"; case George: return "Harrison"; case Ringo: return "Starr"; default: break; } return ""; } }
nested classes—when and how
Java has several features called “nested” or “enclosed” classes. One class can defined within the code body of another class’ definition (indeed a class can be defined, within any code block.) The relationship between the inner and outer classes vary with the kind of nesting.
These features do not exist in all object-oriented languages: C++ has nested classes that correspond to Java static nested classes, but nothing corresponding to the non-static ones. It isn’t something essential to object-oriented programming.
Nested classes turn out to be very handy in some circumstances, and can result in cleaner, more transparent code. But they are often misused too.
This is my collection of rules of thumb and techniques for nested classes.
basic use of nested classes
static vs. non-static inner classes
An instance plain inner class (without the static
keyword), is
dependent on an instance of the outer class. An instance of the inner
class can be created only in reference to an instance of the outer class.
Importantly, the public and protected members of the outer class are
directly accessible to the code of the inner class, as though they were
members of the inner class.
Since a non-static inner class is always associated with its containing class, constructors for the inner class are only meaningful in non-static code of the containing class. An instance of the containing class can create as many instances of its inner classes as desired however. CHECK THIS
class Outer { private int outerField; private void overridable() { } class Inner { void innerMethod() { outerField = 0; // access Outer class member // pass this as instance of Outer someObject.methodRequiringOuter( Outer.this ); } private void overridable() { // override Outer method Outer.overridable(); // call Outer method of same name } } }
The scope keyword static
applied to an inner class definition
effectively makes it independent of its containing class, except that, to
outside code, it must be referred to via the name of the containing class.
It is like putting the class in the namespace of the outer class.
Since instances of a static inner class have no direct association with instances of their containing class, they also have no association with non-static members of the containing class.
Careful: The direct access to outer class members has some pitfalls. For instance: The compiler does not check to see if the constructor of an inner class uses an outer class member before that member has been initialized.
anonymous inner classes
A class may also be defined anonymously. Anonymous classes are commonly used to create Adaptor classes, which only require one method to be overridden.
The anonymity of these classes reflects the fact that their identity isn’t important to the class model. They are defined only for the specific purpose at hand.
private MyType makeMyType() { return new Adaptor() { // overridden Adaptor members } }
The down-sides are: (1) the notation and even the concept is kind of weird, and very Java-specific. (2) if such an object is returned by a function, conventional code indentation will have its code indented more than that of a named class would be.
Note that there is no sense of overriding a constructor of a superclass of an anonymous class. However, a parameter list in the parentheses following the superclass name will be passed to a matching constructor of a superclass.
Another option is to define an instance of an anonymous subclass of an Adaptor in a variable. This at least doesn’t require deeper indentation.
private Adaptor myVarName = new Adaptor() { // overridden Adaptor members }
The down-side of this technique is, the variable’s initialization code must execute before it is passed to some method (of course), but with nested classes, it may be unclear which code is executed first.
referring to outer class from the inner
The instance of the containing class is referred to from an instance of
an inner class by the special notation outer.this
.
Similarly, if the name of a member of the inner class shadows the name
of a member of the containing class, the containing class member can be
accessed by the special notation
outer.member
when to use nested classes
when to use a normal inner class
The natural purpose for nested classes, is to model a notion of containment.
For instance, a special dialog window might contain a class of controls that are meaningful only within that dialog.
The coding advantage of properly modeled inner classes is, the code doesn’t have to set up references between the contained and container class. A normal inner class already has access to its container members.
On the other hand, a class definition is made longer and possibly harder to follow by the presence of an inner class. Unless the nesting means something in the model, it is probably a mistake.
Also, for reasons of readability, inner classes ought to be very simple in structure, with very few members, or simple lists. Likewise, deep nesting of classes would be hard to defend. The loss of readability of complex inner classes probably outweighs the advantages gained by the affinity with outer classes.
A named, non-static inner class should satisfy all these criteria:
- instances of inner class are somehow conceptually contained by instances of the outer class
- inner class code is simple
- inner class code benefits from direct access to outer class’ members.