Sie sind auf Seite 1von 251

2009 JavaOne ™

Best Sellers
Sample Excerpts from 2009 JavaOne Best Selling Titles

informit.com/learnjava

Java_cover.indd 1 6/18/09 9:20:52 AM


2009 JavaOne ™

Best Sellers
eBOOK TABLE OF CONTENTS

• On Software Podcast Channel LEARN MORE… • InformIT LEARN MORE…


• Safari Books Online LEARN MORE… • Learn Java™ Web Page LEARN MORE…

Effective Java™, Java Concurrency in Practice


Second Edition 9780321349606
9780321356680 Brian Goetz, et al
Joshua Bloch CHAPTER 6: Task Execution
CHAPTER 2: Creating and
Destroying Objects

Essential JavaFX Real-Time Java Programming


9780137042791 9780137142989
Gail Anderson, Paul Anderson Eric J. Bruno, Greg Bollella
CHAPTER 2: A Taste of JavaFx CHAPTER 1: Real-Time for the
Rest of Us

Java™ Puzzlers The iPhone Developer’s


9780321336781 Cookbook
Joshua Bloch, Neal Gafter 9780321555458

A Java Puzzlers Sample Erica Sadun


CHAPTER 2: Views

JavaFX The Pragmatic Programmer


97801370128790 9780201616224
Jim Clark, Jim Connors, Eric Bruno Andrew Hunt, David Thomas
CHAPTER 3: JavaFX Primer CHAPTER 1: A Pragmatic
Philosophy

THESE BOOKS ARE AVAILABLE AT BOOKSTORES INCLUDING:

Google
Bookmarks Delicious Digg Facebook StumbleUpon Reddit Twitter

TOC_copyright_java.indd Sec1:1 6/18/09 11:25:39 AM


Many of the designations used by manufacturers and sellers to distinguish their products are claimed
as trademarks. Where those designations appear in this book, and Pearson Education was aware of a
trademark claim, the designations have been printed with initial capital letters or in all capitals.

The authors and publisher have taken care in the preparation of this book, but make no expressed
or implied warranty of any kind and assume no responsibility for errors or omissions. No liability
is assumed for incidental or consequential damages in connection with or arising out of the use of
the information or programs contained herein.

Copyright © 2009 by Pearson Education, Inc.

BROUGHT TO YOU BY

UPPER SADDLE RIVER, NJ | BOSTON | INDIANAPOLIS | SAN FRANCISCO | NEW YORK | TORONTO | MONTREAL | LONDON | MUNICH
PARIS | MADRID | CAPETOWN | SYDNEY | TOKYO | SINGAPORE | MEXICO CITY

TOC_copyright_java.indd Sec1:2 6/18/09 11:27:15 AM


Google
Bookmarks Delicious Digg Facebook StumbleUpon Reddit Twitter

Java_Rock_Star_CH_Openers copy.indd 1 6/18/09 11:34:10 AM


Joshua Bloch

Effective Java, Second Edition

Are you looking for a deeper understanding of the Java™ programming language so
that you can write code that is clearer, more correct, more robust, and more reusable? AVAILABLE
Look no further! Effective Java™, Second Edition, brings together seventy-eight • BOOK: 9780321356680
indispensable programmer’s rules of thumb: working, best-practice solutions for the • SAFARI ONLINE
programming challenges you encounter every day. • EBOOK: 0132345285
This highly anticipated new edition of the classic, Jolt Award-winning work has been • KINDLE: 0137150059
thoroughly updated to cover Java SE 5 and Java SE 6 features introduced since the first
edition. Bloch explores new design patterns and language idioms, showing you how to
About the Author
make the most of features ranging from generics to enums, annotations to autoboxing.
Each chapter in the book consists of several “items” presented in the form of a short, Joshua Bloch is chief Java architect
standalone essay that provides specific advice, insight into Java platform subtleties, and at Google and a Jolt Award winner.
outstanding code examples. The comprehensive descriptions and explanations for each He was previously a distinguished
item illuminate what to do, what not to do, and why. engineer at Sun Microsystems
and a senior systems designer at
Highlights include:
Transarc. Bloch led the design and
• New coverage of generics, enums, annotations, autoboxing, the for-each loop, implementation of numerous Java
varargs, concurrency utilities, and much more platform features, including JDK
• Updated techniques and best practices on classic topics, including objects, classes, 5.0 language enhancements and
libraries, methods, and serialization the award-winning Java Collections
• How to avoid the traps and pitfalls of commonly misunderstood subtleties of the Framework. He coauthored Java™
language Puzzlers (Addison-Wesley, 2005)
• Focus on the language and its most fundamental libraries: java.lang, java.util, and, and Java™ Concurrency in Practice
to a lesser extent, java.util.concurrent and java.io (Addison-Wesley, 2006).
Simply put, Effective Java™, Second Edition, presents the most practical,
authoritative guidelines available for writing efficient, well-designed programs.

informit.com/aw

Java_Rock_Star_CH_Openers copy.indd 2 6/18/09 11:34:12 AM


effective-java.book Page 5 Wednesday, April 23, 2008 4:18 AM

C H A P T E R 2
Creating and Destroying Objects

THIS chapter concerns creating and destroying objects: when and how to create
them, when and how to avoid creating them, how to ensure they are destroyed in a
timely manner, and how to manage any cleanup actions that must precede their
destruction.

Item 1: Consider static factory methods instead of constructors

The normal way for a class to allow a client to obtain an instance of itself is to pro-
vide a public constructor. There is another technique that should be a part of every
programmer’s toolkit. A class can provide a public static factory method, which is
simply a static method that returns an instance of the class. Here’s a simple exam-
ple from Boolean (the boxed primitive class for the primitive type boolean). This
method translates a boolean primitive value into a Boolean object reference:

public static Boolean valueOf(boolean b) {


return b ? Boolean.TRUE : Boolean.FALSE;
}

Note that a static factory method is not the same as the Factory Method pattern
from Design Patterns [Gamma95, p. 107]. The static factory method described in
this item has no direct equivalent in Design Patterns.
A class can provide its clients with static factory methods instead of, or in
addition to, constructors. Providing a static factory method instead of a public
constructor has both advantages and disadvantages.
One advantage of static factory methods is that, unlike constructors, they
have names. If the parameters to a constructor do not, in and of themselves,
describe the object being returned, a static factory with a well-chosen name is eas-
ier to use and the resulting client code easier to read. For example, the constructor

3
effective-java.book Page 6 Friday, May 23, 2008 1:27 PM

4 CHAPTER 2 CREATING AND DESTROYING OBJECTS

BigInteger(int, int, Random), which returns a BigInteger that is probably


prime, would have been better expressed as a static factory method named BigIn-
teger.probablePrime. (This method was eventually added in release 1.4.)
A class can have only a single constructor with a given signature. Program-
mers have been known to get around this restriction by providing two constructors
whose parameter lists differ only in the order of their parameter types. This is a
really bad idea. The user of such an API will never be able to remember which
constructor is which and will end up calling the wrong one by mistake. People
reading code that uses these constructors will not know what the code does with-
out referring to the class documentation.
Because they have names, static factory methods don’t share the restriction
discussed in the previous paragraph. In cases where a class seems to require multi-
ple constructors with the same signature, replace the constructors with static fac-
tory methods and carefully chosen names to highlight their differences.
A second advantage of static factory methods is that, unlike constructors,
they are not required to create a new object each time they’re invoked. This
allows immutable classes (Item 15) to use preconstructed instances, or to cache
instances as they’re constructed, and dispense them repeatedly to avoid creating
unnecessary duplicate objects. The Boolean.valueOf(boolean) method illus-
trates this technique: it never creates an object. This technique is similar to the
Flyweight pattern [Gamma95, p. 195]. It can greatly improve performance if
equivalent objects are requested often, especially if they are expensive to create.
The ability of static factory methods to return the same object from repeated
invocations allows classes to maintain strict control over what instances exist at
any time. Classes that do this are said to be instance-controlled. There are several
reasons to write instance-controlled classes. Instance control allows a class to
guarantee that it is a singleton (Item 3) or noninstantiable (Item 4). Also, it allows
an immutable class (Item 15) to make the guarantee that no two equal instances
exist: a.equals(b) if and only if a==b. If a class makes this guarantee, then its cli-
ents can use the == operator instead of the equals(Object) method, which may
result in improved performance. Enum types (Item 30) provide this guarantee.
A third advantage of static factory methods is that, unlike constructors,
they can return an object of any subtype of their return type. This gives you
great flexibility in choosing the class of the returned object.
One application of this flexibility is that an API can return objects without
making their classes public. Hiding implementation classes in this fashion leads to
a very compact API. This technique lends itself to interface-based frameworks
(Item 18), where interfaces provide natural return types for static factory methods.
effective-java.book Page 7 Wednesday, April 23, 2008 4:18 AM

ITEM 1: CONSIDER STATIC FACTORY METHODS INSTEAD OF CONSTRUCTORS 5

Interfaces can’t have static methods, so by convention, static factory methods for
an interface named Type are put in a noninstantiable class (Item 4) named Types.
For example, the Java Collections Framework has thirty-two convenience
implementations of its collection interfaces, providing unmodifiable collections,
synchronized collections, and the like. Nearly all of these implementations are
exported via static factory methods in one noninstantiable class (java.util.Col-
lections). The classes of the returned objects are all nonpublic.
The Collections Framework API is much smaller than it would have been had
it exported thirty-two separate public classes, one for each convenience imple-
mentation. It is not just the bulk of the API that is reduced, but the conceptual
weight. The user knows that the returned object has precisely the API specified by
its interface, so there is no need to read additional class documentation for the
implementation classes. Furthermore, using such a static factory method requires
the client to refer to the returned object by its interface rather than its implementa-
tion class, which is generally good practice (Item 52).
Not only can the class of an object returned by a public static factory method
be nonpublic, but the class can vary from invocation to invocation depending on
the values of the parameters to the static factory. Any class that is a subtype of the
declared return type is permissible. The class of the returned object can also vary
from release to release for enhanced software maintainability and performance.
The class java.util.EnumSet (Item 32), introduced in release 1.5, has no
public constructors, only static factories. They return one of two implementations,
depending on the size of the underlying enum type: if it has sixty-four or fewer
elements, as most enum types do, the static factories return a RegularEnumSet
instance, which is backed by a single long; if the enum type has sixty-five or more
elements, the factories return a JumboEnumSet instance, backed by a long array.
The existence of these two implementation classes is invisible to clients. If
RegularEnumSet ceased to offer performance advantages for small enum types, it
could be eliminated from a future release with no ill effects. Similarly, a future
release could add a third or fourth implementation of EnumSet if it proved benefi-
cial for performance. Clients neither know nor care about the class of the object
they get back from the factory; they care only that it is some subclass of EnumSet.
The class of the object returned by a static factory method need not even exist
at the time the class containing the method is written. Such flexible static factory
methods form the basis of service provider frameworks, such as the Java Database
Connectivity API (JDBC). A service provider framework is a system in which
multiple service providers implement a service, and the system makes the imple-
mentations available to its clients, decoupling them from the implementations.
effective-java.book Page 8 Wednesday, April 23, 2008 4:18 AM

6 CHAPTER 2 CREATING AND DESTROYING OBJECTS

There are three essential components of a service provider framework: a ser-


vice interface, which providers implement; a provider registration API, which the
system uses to register implementations, giving clients access to them; and a ser-
vice access API, which clients use to obtain an instance of the service. The service
access API typically allows but does not require the client to specify some criteria
for choosing a provider. In the absence of such a specification, the API returns an
instance of a default implementation. The service access API is the “flexible static
factory” that forms the basis of the service provider framework.
An optional fourth component of a service provider framework is a service
provider interface, which providers implement to create instances of their service
implementation. In the absence of a service provider interface, implementations
are registered by class name and instantiated reflectively (Item 53). In the case of
JDBC, Connection plays the part of the service interface, DriverManager.reg-
isterDriver is the provider registration API, DriverManager.getConnection is
the service access API, and Driver is the service provider interface.
There are numerous variants of the service provider framework pattern. For
example, the service access API can return a richer service interface than the one
required of the provider, using the Adapter pattern [Gamma95, p. 139]. Here is a
simple implementation with a service provider interface and a default provider:

// Service provider framework sketch

// Service interface
public interface Service {
... // Service-specific methods go here
}

// Service provider interface


public interface Provider {
Service newService();
}

// Noninstantiable class for service registration and access


public class Services {
private Services() { } // Prevents instantiation (Item 4)

// Maps service names to services


private static final Map<String, Provider> providers =
new ConcurrentHashMap<String, Provider>();
public static final String DEFAULT_PROVIDER_NAME = "<def>";
effective-java.book Page 9 Tuesday, January 20, 2009 10:31 AM

ITEM 1: CONSIDER STATIC FACTORY METHODS INSTEAD OF CONSTRUCTORS 7

// Provider registration API


public static void registerDefaultProvider(Provider p) {
registerProvider(DEFAULT_PROVIDER_NAME, p);
}
public static void registerProvider(String name, Provider p){
providers.put(name, p);
}

// Service access API


public static Service newInstance() {
return newInstance(DEFAULT_PROVIDER_NAME);
}
public static Service newInstance(String name) {
Provider p = providers.get(name);
if (p == null)
throw new IllegalArgumentException(
"No provider registered with name: " + name);
return p.newService();
}
}

A fourth advantage of static factory methods is that they reduce the ver-
bosity of creating parameterized type instances. Unfortunately, you must spec-
ify the type parameters when you invoke the constructor of a parameterized class
even if they’re obvious from context. This typically requires you to provide the
type parameters twice in quick succession:

Map<String, List<String>> m =
new HashMap<String, List<String>>();

This redundant specification quickly becomes painful as the length and complex-
ity of the type parameters increase. With static factories, however, the compiler
can figure out the type parameters for you. This is known as type inference. For
example, suppose that HashMap provided this generic static factory (Item 27):

public static <K, V> HashMap<K, V> newInstance() {


return new HashMap<K, V>();
}

Then you could replace the wordy declaration above with this succinct alternative:

Map<String, List<String>> m = HashMap.newInstance();

Someday the language may perform this sort of type inference on constructor
invocations as well as method invocations, but as of release 1.6, it does not.
effective-java.book Page 10 Wednesday, April 23, 2008 4:18 AM

8 CHAPTER 2 CREATING AND DESTROYING OBJECTS

Unfortunately, the standard collection implementations such as HashMap do


not have factory methods as of release 1.6, but you can put these methods in your
own utility class. More importantly, you can provide such static factories in your
own parameterized classes.
The main disadvantage of providing only static factory methods is that
classes without public or protected constructors cannot be subclassed. The
same is true for nonpublic classes returned by public static factories. For example,
it is impossible to subclass any of the convenience implementation classes in the
Collections Framework. Arguably this can be a blessing in disguise, as it encour-
ages programmers to use composition instead of inheritance (Item 16).
A second disadvantage of static factory methods is that they are not
readily distinguishable from other static methods. They do not stand out in API
documentation in the way that constructors do, so it can be difficult to figure out
how to instantiate a class that provides static factory methods instead of construc-
tors. The Javadoc tool may someday draw attention to static factory methods. In
the meantime, you can reduce this disadvantage by drawing attention to static fac-
tories in class or interface comments, and by adhering to common naming conven-
tions. Here are some common names for static factory methods:

• valueOf—Returns an instance that has, loosely speaking, the same value as its
parameters. Such static factories are effectively type-conversion methods.
• of—A concise alternative to valueOf, popularized by EnumSet (Item 32).
• getInstance—Returns an instance that is described by the parameters but
cannot be said to have the same value. In the case of a singleton, getInstance
takes no parameters and returns the sole instance.
• newInstance—Like getInstance, except that newInstance guarantees that
each instance returned is distinct from all others.
• getType—Like getInstance, but used when the factory method is in a differ-
ent class. Type indicates the type of object returned by the factory method.
• newType—Like newInstance, but used when the factory method is in a differ-
ent class. Type indicates the type of object returned by the factory method.

In summary, static factory methods and public constructors both have their
uses, and it pays to understand their relative merits. Often static factories are pref-
erable, so avoid the reflex to provide public constructors without first considering
static factories.
effective-java.book Page 11 Wednesday, April 23, 2008 4:18 AM

ITEM 2: CONSIDER A BUILDER WHEN FACED WITH MANY CONSTRUCTOR PARAMETERS 9

Item 2: Consider a builder when faced with many constructor


parameters

Static factories and constructors share a limitation: they do not scale well to large
numbers of optional parameters. Consider the case of a class representing the
Nutrition Facts label that appears on packaged foods. These labels have a few
required fields—serving size, servings per container, and calories per serving—
and over twenty optional fields—total fat, saturated fat, trans fat, cholesterol,
sodium, and so on. Most products have nonzero values for only a few of these
optional fields.
What sort of constructors or static factories should you write for such a class?
Traditionally, programmers have used the telescoping constructor pattern, in
which you provide a constructor with only the required parameters, another with a
single optional parameter, a third with two optional parameters, and so on, culmi-
nating in a constructor with all the optional parameters. Here’s how it looks in
practice. For brevity’s sake, only four optional fields are shown:

// Telescoping constructor pattern - does not scale well!


public class NutritionFacts {
private final int servingSize; // (mL) required
private final int servings; // (per container) required
private final int calories; // optional
private final int fat; // (g) optional
private final int sodium; // (mg) optional
private final int carbohydrate; // (g) optional

public NutritionFacts(int servingSize, int servings) {


this(servingSize, servings, 0);
}

public NutritionFacts(int servingSize, int servings,


int calories) {
this(servingSize, servings, calories, 0);
}

public NutritionFacts(int servingSize, int servings,


int calories, int fat) {
this(servingSize, servings, calories, fat, 0);
}

public NutritionFacts(int servingSize, int servings,


int calories, int fat, int sodium) {
this(servingSize, servings, calories, fat, sodium, 0);
}
effective-java.book Page 12 Wednesday, April 23, 2008 4:18 AM

10 CHAPTER 2 CREATING AND DESTROYING OBJECTS

public NutritionFacts(int servingSize, int servings,


int calories, int fat, int sodium, int carbohydrate) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbohydrate;
}
}

When you want to create an instance, you use the constructor with the shortest
parameter list containing all the parameters you want to set:

NutritionFacts cocaCola =
new NutritionFacts(240, 8, 100, 0, 35, 27);

Typically this constructor invocation will require many parameters that you don’t
want to set, but you’re forced to pass a value for them anyway. In this case, we
passed a value of 0 for fat. With “only” six parameters this may not seem so bad,
but it quickly gets out of hand as the number of parameters increases.
In short, the telescoping constructor pattern works, but it is hard to write
client code when there are many parameters, and harder still to read it. The
reader is left wondering what all those values mean and must carefully count
parameters to find out. Long sequences of identically typed parameters can cause
subtle bugs. If the client accidentally reverses two such parameters, the compiler
won’t complain, but the program will misbehave at runtime (Item 40).
A second alternative when you are faced with many constructor parameters is
the JavaBeans pattern, in which you call a parameterless constructor to create the
object and then call setter methods to set each required parameter and each
optional parameter of interest:

// JavaBeans Pattern - allows inconsistency, mandates mutability


public class NutritionFacts {
// Parameters initialized to default values (if any)
private int servingSize = -1; // Required; no default value
private int servings = -1; // " " " "
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;

public NutritionFacts() { }
effective-java.book Page 13 Wednesday, April 23, 2008 4:18 AM

ITEM 2: CONSIDER A BUILDER WHEN FACED WITH MANY CONSTRUCTOR PARAMETERS 11

// Setters
public void setServingSize(int val) { servingSize = val; }
public void setServings(int val) { servings = val; }
public void setCalories(int val) { calories = val; }
public void setFat(int val) { fat = val; }
public void setSodium(int val) { sodium = val; }
public void setCarbohydrate(int val) { carbohydrate = val; }
}

This pattern has none of the disadvantages of the telescoping constructor pattern.
It is easy, if a bit wordy, to create instances, and easy to read the resulting code:

NutritionFacts cocaCola = new NutritionFacts();


cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);

Unfortunately, the JavaBeans pattern has serious disadvantages of its own.


Because construction is split across multiple calls, a JavaBean may be in an
inconsistent state partway through its construction. The class does not have
the option of enforcing consistency merely by checking the validity of the con-
structor parameters. Attempting to use an object when it’s in an inconsistent state
may cause failures that are far removed from the code containing the bug, hence
difficult to debug. A related disadvantage is that the JavaBeans pattern pre-
cludes the possibility of making a class immutable (Item 15), and requires
added effort on the part of the programmer to ensure thread safety.
It is possible to reduce these disadvantages by manually “freezing” the object
when its construction is complete and not allowing it to be used until frozen, but
this variant is unwieldy and rarely used in practice. Moreover, it can cause errors
at runtime, as the compiler cannot ensure that the programmer calls the freeze
method on an object before using it.
Luckily, there is a third alternative that combines the safety of the telescoping
constructor pattern with the readability of the JavaBeans pattern. It is a form of the
Builder pattern [Gamma95, p. 97]. Instead of making the desired object directly,
the client calls a constructor (or static factory) with all of the required parameters
and gets a builder object. Then the client calls setter-like methods on the builder
object to set each optional parameter of interest. Finally, the client calls a parame-
terless build method to generate the object, which is immutable. The builder is a
static member class (Item 22) of the class it builds. Here’s how it looks in practice:
effective-java.book Page 14 Wednesday, April 23, 2008 4:18 AM

12 CHAPTER 2 CREATING AND DESTROYING OBJECTS

// Builder Pattern
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;

public static class Builder {


// Required parameters
private final int servingSize;
private final int servings;

// Optional parameters - initialized to default values


private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;

public Builder(int servingSize, int servings) {


this.servingSize = servingSize;
this.servings = servings;
}

public Builder calories(int val)


{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }
public Builder carbohydrate(int val)
{ carbohydrate = val; return this; }
public Builder sodium(int val)
{ sodium = val; return this; }

public NutritionFacts build() {


return new NutritionFacts(this);
}
}

private NutritionFacts(Builder builder) {


servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
effective-java.book Page 15 Tuesday, January 20, 2009 10:31 AM

ITEM 2: CONSIDER A BUILDER WHEN FACED WITH MANY CONSTRUCTOR PARAMETERS 13

Note that NutritionFacts is immutable, and that all parameter default values
are in a single location. The builder’s setter methods return the builder itself so
that invocations can be chained. Here’s how the client code looks:

NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).


calories(100).sodium(35).carbohydrate(27).build();

This client code is easy to write and, more importantly, to read. The Builder pat-
tern simulates named optional parameters as found in Ada and Python.
Like a constructor, a builder can impose invariants on its parameters. The
build method can check these invariants. It is critical that they be checked after
copying the parameters from the builder to the object, and that they be checked on
the object fields rather than the builder fields (Item 39). If any invariants are vio-
lated, the build method should throw an IllegalStateException (Item 60). The
exception’s detail message should indicate which invariant is violated (Item 63).
Another way to impose invariants involving multiple parameters is to have
setter methods take entire groups of parameters on which some invariant must
hold. If the invariant isn’t satisfied, the setter method throws an IllegalArgumen-
tException. This has the advantage of detecting the invariant failure as soon as
the invalid parameters are passed, instead of waiting for build to be invoked.
A minor advantage of builders over constructors is that builders can have mul-
tiple varargs parameters. Constructors, like methods, can have only one varargs
parameter. Because builders use separate methods to set each parameter, they can
have as many varargs parameters as you like, up to one per setter method.
The Builder pattern is flexible. A single builder can be used to build multiple
objects. The parameters of the builder can be tweaked between object creations to
vary the objects. The builder can fill in some fields automatically, such as a serial
number that automatically increases each time an object is created.
A builder whose parameters have been set makes a fine Abstract Factory
[Gamma95, p. 87]. In other words, a client can pass such a builder to a method to
enable the method to create one or more objects for the client. To enable this
usage, you need a type to represent the builder. If you are using release 1.5 or a
later release, a single generic type (Item 26) suffices for all builders, no matter
what type of object they’re building:

// A builder for objects of type T


public interface Builder<T> {
public T build();
}
effective-java.book Page 16 Wednesday, April 23, 2008 4:18 AM

14 CHAPTER 2 CREATING AND DESTROYING OBJECTS

Note that our NutritionFacts.Builder class could be declared to implement


Builder<NutritionFacts>.
Methods that take a Builder instance would typically constrain the builder’s
type parameter using a bounded wildcard type (Item 28). For example, here is a
method that builds a tree using a client-provided Builder instance to build each
node:

Tree buildTree(Builder<? extends Node> nodeBuilder) { ... }

The traditional Abstract Factory implementation in Java has been the Class
object, with the newInstance method playing the part of the build method. This
usage is fraught with problems. The newInstance method always attempts to
invoke the class’s parameterless constructor, which may not even exist. You don’t
get a compile-time error if the class has no accessible parameterless constructor.
Instead, the client code must cope with InstantiationException or IllegalAc-
cessException at runtime, which is ugly and inconvenient. Also, the newIn-
stance method propagates any exceptions thrown by the parameterless
constructor, even though newInstance lacks the corresponding throws clauses. In
other words, Class.newInstance breaks compile-time exception checking. The
Builder interface, shown above, corrects these deficiencies.
The Builder pattern does have disadvantages of its own. In order to create an
object, you must first create its builder. While the cost of creating the builder is
unlikely to be noticeable in practice, it could be a problem in some performance-
critical situations. Also, the Builder pattern is more verbose than the telescoping
constructor pattern, so it should be used only if there are enough parameters, say,
four or more. But keep in mind that you may want to add parameters in the future.
If you start out with constructors or static factories, and add a builder when the
class evolves to the point where the number of parameters starts to get out of hand,
the obsolete constructors or static factories will stick out like a sore thumb. There-
fore, it’s often better to start with a builder in the first place.
In summary, the Builder pattern is a good choice when designing classes
whose constructors or static factories would have more than a handful of
parameters, especially if most of those parameters are optional. Client code is
much easier to read and write with builders than with the traditional telescoping
constructor pattern, and builders are much safer than JavaBeans.
effective-java.book Page 17 Wednesday, April 23, 2008 4:18 AM

ITEM 3: ENFORCE THE SINGLETON PROPERTY WITH A PRIVATE CONSTRUCTOR OR AN ENUM TYPE 15

Item 3: Enforce the singleton property with a private


constructor or an enum type

A singleton is simply a class that is instantiated exactly once [Gamma95, p. 127].


Singletons typically represent a system component that is intrinsically unique,
such as the window manager or file system. Making a class a singleton can
make it difficult to test its clients, as it’s impossible to substitute a mock imple-
mentation for a singleton unless it implements an interface that serves as its type.
Before release 1.5, there were two ways to implement singletons. Both are
based on keeping the constructor private and exporting a public static member to
provide access to the sole instance. In one approach, the member is a final field:

// Singleton with public final field


public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }

public void leaveTheBuilding() { ... }


}

The private constructor is called only once, to initialize the public static final field
Elvis.INSTANCE. The lack of a public or protected constructor guarantees a
“monoelvistic” universe: exactly one Elvis instance will exist once the Elvis
class is initialized—no more, no less. Nothing that a client does can change this,
with one caveat: a privileged client can invoke the private constructor reflectively
(Item 53) with the aid of the AccessibleObject.setAccessible method. If you
need to defend against this attack, modify the constructor to make it throw an
exception if it’s asked to create a second instance.
In the second approach to implementing singletons, the public member is a
static factory method:

// Singleton with static factory


public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() { return INSTANCE; }

public void leaveTheBuilding() { ... }


}

All calls to Elvis.getInstance return the same object reference, and no other
Elvis instance will ever be created (with the same caveat mentioned above).
effective-java.book Page 18 Friday, May 23, 2008 2:00 PM

16 CHAPTER 2 CREATING AND DESTROYING OBJECTS

The main advantage of the public field approach is that the declarations make
it clear that the class is a singleton: the public static field is final, so it will always
contain the same object reference. There is no longer any performance advantage
to the public field approach: modern Java virtual machine (JVM) implementations
are almost certain to inline the call to the static factory method.
One advantage of the factory-method approach is that it gives you the flexibil-
ity to change your mind about whether the class should be a singleton without
changing its API. The factory method returns the sole instance but could easily be
modified to return, say, a unique instance for each thread that invokes it. A second
advantage, concerning generic types, is discussed in Item 27. Often neither of
these advantages is relevant, and the public field approach is simpler.
To make a singleton class that is implemented using either of the previous
approaches serializable (Chapter 11), it is not sufficient merely to add imple-
ments Serializable to its declaration. To maintain the singleton guarantee, you
have to declare all instance fields transient and provide a readResolve method
(Item 77). Otherwise, each time a serialized instance is deserialized, a new
instance will be created, leading, in the case of our example, to spurious Elvis
sightings. To prevent this, add this readResolve method to the Elvis class:

// readResolve method to preserve singleton property


private Object readResolve() {
// Return the one true Elvis and let the garbage collector
// take care of the Elvis impersonator.
return INSTANCE;
}

As of release 1.5, there is a third approach to implementing singletons. Simply


make an enum type with one element:

// Enum singleton - the preferred approach


public enum Elvis {
INSTANCE;

public void leaveTheBuilding() { ... }


}

This approach is functionally equivalent to the public field approach, except that it
is more concise, provides the serialization machinery for free, and provides an
ironclad guarantee against multiple instantiation, even in the face of sophisticated
serialization or reflection attacks. While this approach has yet to be widely
adopted, a single-element enum type is the best way to implement a singleton.
effective-java.book Page 19 Wednesday, April 23, 2008 4:18 AM

ITEM 4: ENFORCE NONINSTANTIABILITY WITH A PRIVATE CONSTRUCTOR 17

Item 4: Enforce noninstantiability with a private constructor

Occasionally you’ll want to write a class that is just a grouping of static methods
and static fields. Such classes have acquired a bad reputation because some people
abuse them to avoid thinking in terms of objects, but they do have valid uses. They
can be used to group related methods on primitive values or arrays, in the manner
of java.lang.Math or java.util.Arrays. They can also be used to group static
methods, including factory methods (Item 1), for objects that implement a particu-
lar interface, in the manner of java.util.Collections. Lastly, they can be used
to group methods on a final class, instead of extending the class.
Such utility classes were not designed to be instantiated: an instance would be
nonsensical. In the absence of explicit constructors, however, the compiler pro-
vides a public, parameterless default constructor. To a user, this constructor is
indistinguishable from any other. It is not uncommon to see unintentionally
instantiable classes in published APIs.
Attempting to enforce noninstantiability by making a class abstract does
not work. The class can be subclassed and the subclass instantiated. Furthermore,
it misleads the user into thinking the class was designed for inheritance (Item 17).
There is, however, a simple idiom to ensure noninstantiability. A default construc-
tor is generated only if a class contains no explicit constructors, so a class can be
made noninstantiable by including a private constructor:

// Noninstantiable utility class


public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
... // Remainder omitted
}

Because the explicit constructor is private, it is inaccessible outside of the


class. The AssertionError isn’t strictly required, but it provides insurance in
case the constructor is accidentally invoked from within the class. It guarantees
that the class will never be instantiated under any circumstances. This idiom is
mildly counterintuitive, as the constructor is provided expressly so that it cannot
be invoked. It is therefore wise to include a comment, as shown above.
As a side effect, this idiom also prevents the class from being subclassed. All
constructors must invoke a superclass constructor, explicitly or implicitly, and a
subclass would have no accessible superclass constructor to invoke.
effective-java.book Page 20 Wednesday, April 23, 2008 4:18 AM

18 CHAPTER 2 CREATING AND DESTROYING OBJECTS

Item 5: Avoid creating unnecessary objects

It is often appropriate to reuse a single object instead of creating a new function-


ally equivalent object each time it is needed. Reuse can be both faster and more
stylish. An object can always be reused if it is immutable (Item 15).
As an extreme example of what not to do, consider this statement:

String s = new String("stringette"); // DON'T DO THIS!

The statement creates a new String instance each time it is executed, and
none of those object creations is necessary. The argument to the String construc-
tor ("stringette") is itself a String instance, functionally identical to all of the
objects created by the constructor. If this usage occurs in a loop or in a frequently
invoked method, millions of String instances can be created needlessly.
The improved version is simply the following:

String s = "stringette";

This version uses a single String instance, rather than creating a new one
each time it is executed. Furthermore, it is guaranteed that the object will be
reused by any other code running in the same virtual machine that happens to con-
tain the same string literal [JLS, 3.10.5].
You can often avoid creating unnecessary objects by using static factory meth-
ods (Item 1) in preference to constructors on immutable classes that provide both.
For example, the static factory method Boolean.valueOf(String) is almost
always preferable to the constructor Boolean(String). The constructor creates a
new object each time it’s called, while the static factory method is never required
to do so and won’t in practice.
In addition to reusing immutable objects, you can also reuse mutable objects
if you know they won’t be modified. Here is a slightly more subtle, and much
more common, example of what not to do. It involves mutable Date objects that
are never modified once their values have been computed. This class models a
person and has an isBabyBoomer method that tells whether the person is a “baby
boomer,” in other words, whether the person was born between 1946 and 1964:

public class Person {


private final Date birthDate;

// Other fields, methods, and constructor omitted


effective-java.book Page 21 Friday, May 23, 2008 1:27 PM

ITEM 5: AVOID CREATING UNNECESSARY OBJECTS 19

// DON'T DO THIS!
public boolean isBabyBoomer() {
// Unnecessary allocation of expensive object
Calendar gmtCal =
Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
Date boomStart = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.getTime();
return birthDate.compareTo(boomStart) >= 0 &&
birthDate.compareTo(boomEnd) < 0;
}
}

The isBabyBoomer method unnecessarily creates a new Calendar, TimeZone,


and two Date instances each time it is invoked. The version that follows avoids
this inefficiency with a static initializer:

public class Person {


private final Date birthDate;
// Other fields, methods, and constructor omitted

/**
* The starting and ending dates of the baby boom.
*/
private static final Date BOOM_START;
private static final Date BOOM_END;

static {
Calendar gmtCal =
Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
}

public boolean isBabyBoomer() {


return birthDate.compareTo(BOOM_START) >= 0 &&
birthDate.compareTo(BOOM_END) < 0;
}
}

The improved version of the Person class creates Calendar, TimeZone, and
Date instances only once, when it is initialized, instead of creating them every
time isBabyBoomer is invoked. This results in significant performance gains if the
effective-java.book Page 22 Wednesday, April 23, 2008 4:18 AM

20 CHAPTER 2 CREATING AND DESTROYING OBJECTS

method is invoked frequently. On my machine, the original version takes 32,000


ms for 10 million invocations, while the improved version takes 130 ms, which is
about 250 times faster. Not only is performance improved, but so is clarity.
Changing boomStart and boomEnd from local variables to static final fields makes
it clear that these dates are treated as constants, making the code more understand-
able. In the interest of full disclosure, the savings from this sort of optimization
will not always be this dramatic, as Calendar instances are particularly expensive
to create.
If the improved version of the Person class is initialized but its isBabyBoomer
method is never invoked, the BOOM_START and BOOM_END fields will be initialized
unnecessarily. It would be possible to eliminate the unnecessary initializations by
lazily initializing these fields (Item 71) the first time the isBabyBoomer method is
invoked, but it is not recommended. As is often the case with lazy initialization, it
would complicate the implementation and would be unlikely to result in a notice-
able performance improvement beyond what we’ve already achieved (Item 55).
In the previous examples in this item, it was obvious that the objects in ques-
tion could be reused because they were not modified after initialization. There are
other situations where it is less obvious. Consider the case of adapters [Gamma95,
p. 139], also known as views. An adapter is an object that delegates to a backing
object, providing an alternative interface to the backing object. Because an adapter
has no state beyond that of its backing object, there’s no need to create more than
one instance of a given adapter to a given object.
For example, the keySet method of the Map interface returns a Set view of the
Map object, consisting of all the keys in the map. Naively, it would seem that every
call to keySet would have to create a new Set instance, but every call to keySet
on a given Map object may return the same Set instance. Although the returned
Set instance is typically mutable, all of the returned objects are functionally iden-
tical: when one of the returned objects changes, so do all the others because
they’re all backed by the same Map instance. While it is harmless to create multiple
instances of the keySet view object, it is also unnecessary.
There’s a new way to create unnecessary objects in release 1.5. It is called
autoboxing, and it allows the programmer to mix primitive and boxed primitive
types, boxing and unboxing automatically as needed. Autoboxing blurs but does
not erase the distinction between primitive and boxed primitive types. There are
subtle semantic distinctions, and not-so-subtle performance differences (Item 49).
Consider the following program, which calculates the sum of all the positive int
effective-java.book Page 23 Tuesday, January 20, 2009 10:31 AM

ITEM 5: AVOID CREATING UNNECESSARY OBJECTS 21

values. To do this, the program has to use long arithmetic, because an int is not
big enough to hold the sum of all the positive int values:

// Hideously slow program! Can you spot the object creation?


public static void main(String[] args) {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}

This program gets the right answer, but it is much slower than it should be,
due to a one-character typographical error. The variable sum is declared as a Long
instead of a long, which means that the program constructs about 231 unnecessary
Long instances (roughly one for each time the long i is added to the Long sum).
Changing the declaration of sum from Long to long reduces the runtime from 43
seconds to 6.8 seconds on my machine. The lesson is clear: prefer primitives to
boxed primitives, and watch out for unintentional autoboxing.
This item should not be misconstrued to imply that object creation is expen-
sive and should be avoided. On the contrary, the creation and reclamation of small
objects whose constructors do little explicit work is cheap, especially on modern
JVM implementations. Creating additional objects to enhance the clarity, simplic-
ity, or power of a program is generally a good thing.
Conversely, avoiding object creation by maintaining your own object pool is a
bad idea unless the objects in the pool are extremely heavyweight. The classic
example of an object that does justify an object pool is a database connection. The
cost of establishing the connection is sufficiently high that it makes sense to reuse
these objects. Also, your database license may limit you to a fixed number of con-
nections. Generally speaking, however, maintaining your own object pools clut-
ters your code, increases memory footprint, and harms performance. Modern
JVM implementations have highly optimized garbage collectors that easily out-
perform such object pools on lightweight objects.
The counterpoint to this item is Item 39 on defensive copying. Item 5 says,
“Don’t create a new object when you should reuse an existing one,” while Item 39
says, “Don’t reuse an existing object when you should create a new one.” Note
that the penalty for reusing an object when defensive copying is called for is far
greater than the penalty for needlessly creating a duplicate object. Failing to make
defensive copies where required can lead to insidious bugs and security holes; cre-
ating objects unnecessarily merely affects style and performance.
effective-java.book Page 24 Wednesday, April 23, 2008 4:18 AM

22 CHAPTER 2 CREATING AND DESTROYING OBJECTS

Item 6: Eliminate obsolete object references

When you switch from a language with manual memory management, such as C
or C++, to a garbage-collected language, your job as a programmer is made much
easier by the fact that your objects are automatically reclaimed when you’re
through with them. It seems almost like magic when you first experience it. It can
easily lead to the impression that you don’t have to think about memory manage-
ment, but this isn’t quite true.
Consider the following simple stack implementation:

// Can you spot the "memory leak"?


public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;

public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}

public void push(Object e) {


ensureCapacity();
elements[size++] = e;
}

public Object pop() {


if (size == 0)
throw new EmptyStackException();
return elements[--size];
}

/**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}

There’s nothing obviously wrong with this program (but see Item 26 for a
generic version). You could test it exhaustively, and it would pass every test with
flying colors, but there’s a problem lurking. Loosely speaking, the program has a
“memory leak,” which can silently manifest itself as reduced performance due to
effective-java.book Page 25 Wednesday, April 23, 2008 4:18 AM

ITEM 6: ELIMINATE OBSOLETE OBJECT REFERENCES 23

increased garbage collector activity or increased memory footprint. In extreme


cases, such memory leaks can cause disk paging and even program failure with an
OutOfMemoryError, but such failures are relatively rare.
So where is the memory leak? If a stack grows and then shrinks, the objects
that were popped off the stack will not be garbage collected, even if the program
using the stack has no more references to them. This is because the stack main-
tains obsolete references to these objects. An obsolete reference is simply a refer-
ence that will never be dereferenced again. In this case, any references outside of
the “active portion” of the element array are obsolete. The active portion consists
of the elements whose index is less than size.
Memory leaks in garbage-collected languages (more properly known as unin-
tentional object retentions) are insidious. If an object reference is unintentionally
retained, not only is that object excluded from garbage collection, but so too are
any objects referenced by that object, and so on. Even if only a few object refer-
ences are unintentionally retained, many, many objects may be prevented from
being garbage collected, with potentially large effects on performance.
The fix for this sort of problem is simple: null out references once they
become obsolete. In the case of our Stack class, the reference to an item becomes
obsolete as soon as it’s popped off the stack. The corrected version of the pop
method looks like this:

public Object pop() {


if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}

An added benefit of nulling out obsolete references is that, if they are subse-
quently dereferenced by mistake, the program will immediately fail with a
NullPointerException, rather than quietly doing the wrong thing. It is always
beneficial to detect programming errors as quickly as possible.
When programmers are first stung by this problem, they may overcompensate
by nulling out every object reference as soon as the program is finished using it.
This is neither necessary nor desirable, as it clutters up the program unnecessarily.
Nulling out object references should be the exception rather than the norm.
The best way to eliminate an obsolete reference is to let the variable that contained
the reference fall out of scope. This occurs naturally if you define each variable in
the narrowest possible scope (Item 45).
effective-java.book Page 26 Wednesday, April 23, 2008 4:18 AM

24 CHAPTER 2 CREATING AND DESTROYING OBJECTS

So when should you null out a reference? What aspect of the Stack class
makes it susceptible to memory leaks? Simply put, it manages its own memory.
The storage pool consists of the elements of the elements array (the object refer-
ence cells, not the objects themselves). The elements in the active portion of the
array (as defined earlier) are allocated, and those in the remainder of the array are
free. The garbage collector has no way of knowing this; to the garbage collector,
all of the object references in the elements array are equally valid. Only the pro-
grammer knows that the inactive portion of the array is unimportant. The pro-
grammer effectively communicates this fact to the garbage collector by manually
nulling out array elements as soon as they become part of the inactive portion.
Generally speaking, whenever a class manages its own memory, the pro-
grammer should be alert for memory leaks. Whenever an element is freed, any
object references contained in the element should be nulled out.
Another common source of memory leaks is caches. Once you put an
object reference into a cache, it’s easy to forget that it’s there and leave it in the
cache long after it becomes irrelevant. There are several solutions to this problem.
If you’re lucky enough to implement a cache for which an entry is relevant exactly
so long as there are references to its key outside of the cache, represent the cache
as a WeakHashMap; entries will be removed automatically after they become obso-
lete. Remember that WeakHashMap is useful only if the desired lifetime of cache
entries is determined by external references to the key, not the value.
More commonly, the useful lifetime of a cache entry is less well defined, with
entries becoming less valuable over time. Under these circumstances, the cache
should occasionally be cleansed of entries that have fallen into disuse. This can be
done by a background thread (perhaps a Timer or ScheduledThreadPoolExecu-
tor) or as a side effect of adding new entries to the cache. The LinkedHashMap
class facilitates the latter approach with its removeEldestEntry method. For
more sophisticated caches, you may need to use java.lang.ref directly.
A third common source of memory leaks is listeners and other callbacks.
If you implement an API where clients register callbacks but don’t deregister them
explicitly, they will accumulate unless you take some action. The best way to
ensure that callbacks are garbage collected promptly is to store only weak refer-
ences to them, for instance, by storing them only as keys in a WeakHashMap.
Because memory leaks typically do not manifest themselves as obvious fail-
ures, they may remain present in a system for years. They are typically discovered
only as a result of careful code inspection or with the aid of a debugging tool
known as a heap profiler. Therefore, it is very desirable to learn to anticipate prob-
lems like this before they occur and prevent them from happening.
effective-java.book Page 27 Wednesday, April 23, 2008 4:18 AM

ITEM 7: AVOID FINALIZERS 25

Item 7: Avoid finalizers

Finalizers are unpredictable, often dangerous, and generally unnecessary.


Their use can cause erratic behavior, poor performance, and portability problems.
Finalizers have a few valid uses, which we’ll cover later in this item, but as a rule
of thumb, you should avoid finalizers.
C++ programmers are cautioned not to think of finalizers as Java’s analog of
C++ destructors. In C++, destructors are the normal way to reclaim the resources
associated with an object, a necessary counterpart to constructors. In Java, the gar-
bage collector reclaims the storage associated with an object when it becomes
unreachable, requiring no special effort on the part of the programmer. C++
destructors are also used to reclaim other nonmemory resources. In Java, the try-
finally block is generally used for this purpose.
One shortcoming of finalizers is that there is no guarantee they’ll be executed
promptly [JLS, 12.6]. It can take arbitrarily long between the time that an object
becomes unreachable and the time that its finalizer is executed. This means that
you should never do anything time-critical in a finalizer. For example, it is a
grave error to depend on a finalizer to close files, because open file descriptors are
a limited resource. If many files are left open because the JVM is tardy in execut-
ing finalizers, a program may fail because it can no longer open files.
The promptness with which finalizers are executed is primarily a function of
the garbage collection algorithm, which varies widely from JVM implementation
to JVM implementation. The behavior of a program that depends on the prompt-
ness of finalizer execution may likewise vary. It is entirely possible that such a
program will run perfectly on the JVM on which you test it and then fail miserably
on the JVM favored by your most important customer.
Tardy finalization is not just a theoretical problem. Providing a finalizer for a
class can, under rare conditions, arbitrarily delay reclamation of its instances. A
colleague debugged a long-running GUI application that was mysteriously dying
with an OutOfMemoryError. Analysis revealed that at the time of its death, the
application had thousands of graphics objects on its finalizer queue just waiting to
be finalized and reclaimed. Unfortunately, the finalizer thread was running at a
lower priority than another application thread, so objects weren’t getting finalized
at the rate they became eligible for finalization. The language specification makes
no guarantees as to which thread will execute finalizers, so there is no portable
way to prevent this sort of problem other than to refrain from using finalizers.
Not only does the language specification provide no guarantee that finalizers
will get executed promptly; it provides no guarantee that they’ll get executed at
effective-java.book Page 28 Wednesday, April 23, 2008 4:18 AM

26 CHAPTER 2 CREATING AND DESTROYING OBJECTS

all. It is entirely possible, even likely, that a program terminates without executing
finalizers on some objects that are no longer reachable. As a consequence, you
should never depend on a finalizer to update critical persistent state. For
example, depending on a finalizer to release a persistent lock on a shared resource
such as a database is a good way to bring your entire distributed system to a
grinding halt.
Don’t be seduced by the methods System.gc and System.runFinalization.
They may increase the odds of finalizers getting executed, but they don’t guaran-
tee it. The only methods that claim to guarantee finalization are System.runFi-
nalizersOnExit and its evil twin, Runtime.runFinalizersOnExit. These
methods are fatally flawed and have been deprecated [ThreadStop].
In case you are not yet convinced that finalizers should be avoided, here’s
another tidbit worth considering: if an uncaught exception is thrown during final-
ization, the exception is ignored, and finalization of that object terminates [JLS,
12.6]. Uncaught exceptions can leave objects in a corrupt state. If another thread
attempts to use such a corrupted object, arbitrary nondeterministic behavior may
result. Normally, an uncaught exception will terminate the thread and print a stack
trace, but not if it occurs in a finalizer—it won’t even print a warning.
Oh, and one more thing: there is a severe performance penalty for using
finalizers. On my machine, the time to create and destroy a simple object is about
5.6 ns. Adding a finalizer increases the time to 2,400 ns. In other words, it is about
430 times slower to create and destroy objects with finalizers.
So what should you do instead of writing a finalizer for a class whose objects
encapsulate resources that require termination, such as files or threads? Just pro-
vide an explicit termination method, and require clients of the class to invoke this
method on each instance when it is no longer needed. One detail worth mention-
ing is that the instance must keep track of whether it has been terminated: the
explicit termination method must record in a private field that the object is no
longer valid, and other methods must check this field and throw an Illegal-
StateException if they are called after the object has been terminated.
Typical examples of explicit termination methods are the close methods on
InputStream, OutputStream, and java.sql.Connection. Another example is
the cancel method on java.util.Timer, which performs the necessary state
change to cause the thread associated with a Timer instance to terminate itself
gently. Examples from java.awt include Graphics.dispose and Window.dis-
pose. These methods are often overlooked, with predictably dire performance
consequences. A related method is Image.flush, which deallocates all the
effective-java.book Page 29 Wednesday, April 23, 2008 4:18 AM

ITEM 7: AVOID FINALIZERS 27

resources associated with an Image instance but leaves it in a state where it can
still be used, reallocating the resources if necessary.
Explicit termination methods are typically used in combination with the
try-finally construct to ensure termination. Invoking the explicit termination
method inside the finally clause ensures that it will get executed even if an
exception is thrown while the object is being used:

// try-finally block guarantees execution of termination method


Foo foo = new Foo(...);
try {
// Do what must be done with foo
...
} finally {
foo.terminate(); // Explicit termination method
}

So what, if anything, are finalizers good for? There are perhaps two legitimate
uses. One is to act as a “safety net” in case the owner of an object forgets to call its
explicit termination method. While there’s no guarantee that the finalizer will be
invoked promptly, it may be better to free the resource late than never, in those
(hopefully rare) cases when the client fails to call the explicit termination method.
But the finalizer should log a warning if it finds that the resource has not been
terminated, as this indicates a bug in the client code, which should be fixed. If
you are considering writing such a safety-net finalizer, think long and hard about
whether the extra protection is worth the extra cost.
The four classes cited as examples of the explicit termination method pattern
(FileInputStream, FileOutputStream, Timer, and Connection) have finalizers
that serve as safety nets in case their termination methods aren’t called. Unfortu-
nately these finalizers do not log warnings. Such warnings generally can’t be
added after an API is published, as it would appear to break existing clients.
A second legitimate use of finalizers concerns objects with native peers. A
native peer is a native object to which a normal object delegates via native meth-
ods. Because a native peer is not a normal object, the garbage collector doesn’t
know about it and can’t reclaim it when its Java peer is reclaimed. A finalizer is an
appropriate vehicle for performing this task, assuming the native peer holds no
critical resources. If the native peer holds resources that must be terminated
promptly, the class should have an explicit termination method, as described
above. The termination method should do whatever is required to free the critical
resource. The termination method can be a native method, or it can invoke one.
effective-java.book Page 30 Wednesday, April 23, 2008 4:18 AM

28 CHAPTER 2 CREATING AND DESTROYING OBJECTS

It is important to note that “finalizer chaining” is not performed automatically.


If a class (other than Object) has a finalizer and a subclass overrides it, the sub-
class finalizer must invoke the superclass finalizer manually. You should finalize
the subclass in a try block and invoke the superclass finalizer in the correspond-
ing finally block. This ensures that the superclass finalizer gets executed even if
the subclass finalization throws an exception and vice versa. Here’s how it looks.
Note that this example uses the Override annotation (@Override), which was
added to the platform in release 1.5. You can ignore Override annotations for
now, or see Item 36 to find out what they mean:

// Manual finalizer chaining


@Override protected void finalize() throws Throwable {
try {
... // Finalize subclass state
} finally {
super.finalize();
}
}

If a subclass implementor overrides a superclass finalizer but forgets to invoke


it, the superclass finalizer will never be invoked. It is possible to defend against
such a careless or malicious subclass at the cost of creating an additional object
for every object to be finalized. Instead of putting the finalizer on the class
requiring finalization, put the finalizer on an anonymous class (Item 22) whose
sole purpose is to finalize its enclosing instance. A single instance of the
anonymous class, called a finalizer guardian, is created for each instance of the
enclosing class. The enclosing instance stores the sole reference to its finalizer
guardian in a private instance field so the finalizer guardian becomes eligible for
finalization at the same time as the enclosing instance. When the guardian is
finalized, it performs the finalization activity desired for the enclosing instance,
just as if its finalizer were a method on the enclosing class:

// Finalizer Guardian idiom


public class Foo {
// Sole purpose of this object is to finalize outer Foo object
private final Object finalizerGuardian = new Object() {
@Override protected void finalize() throws Throwable {
... // Finalize outer Foo object
}
};
... // Remainder omitted
}
effective-java.book Page 31 Wednesday, April 23, 2008 4:18 AM

ITEM 7: AVOID FINALIZERS 29

Note that the public class, Foo, has no finalizer (other than the trivial one it
inherits from Object), so it doesn’t matter whether a subclass finalizer calls
super.finalize or not. This technique should be considered for every nonfinal
public class that has a finalizer.
In summary, don’t use finalizers except as a safety net or to terminate
noncritical native resources. In those rare instances where you do use a finalizer,
remember to invoke super.finalize. If you use a finalizer as a safety net,
remember to log the invalid usage from the finalizer. Lastly, if you need to
associate a finalizer with a public, nonfinal class, consider using a finalizer
guardian, so finalization can take place even if a subclass finalizer fails to invoke
super.finalize.
Google
Bookmarks Delicious Digg Facebook StumbleUpon Reddit Twitter

Java_Rock_Star_CH_Openers.indd 1 6/18/09 11:42:15 AM


Gail Anderson
Paul Anderson

Essential JavaFx™

JavaFX is a rich-client platform for building applications and expressive content for the
desktop, browsers, and mobile devices. JavaFX applications are written with JavaFX AVAILABLE
Script, a simple, easy-to-learn declarative scripting language. Created to make it easy • BOOK: 9780137042791
for web developers and GUI designers to collaborate, JavaFX Script also includes a • SAFARI ONLINE
powerful data binding feature that allows graphical components to automatically change • EBOOK: 0137044550
state when underlying data is changed. • KINDLE: 0137044313

Essential JavaFX™ clearly explains everything you need to know to write JavaFX
scripts that leverage the language’s unique features for creating rich content. Starting About the Authors
with the fundamentals, this practical tutorial introduces the JavaFX scene graph and Gail Anderson is a software
covers the most effective uses of binding, event handlers, and animation, as well as specialist and author who has written
how to use mixin inheritance. Each chapter includes one or more JavaFX application numerous books on leading-edge
examples. Java technologies. Gail is a founding
member of the Anderson Software
Key topics covered include: Group, Inc., a leading provider
of software development training
• Shapes, Paths, and Path Elements courses.
• Layout Nodes and Bounding Rectangles
• JavaFX UI Controls and JavaFX Swing Components Paul Anderson is a founding
• Custom Skinnable Components member of the Anderson Software
• Images and ImageViewers Group, Inc., and a leading trainer in
• Using Web Services software technologies, such as Java,
• Targeting the Mobile Environment C++, C#, Perl, UML, and Linux. Paul
has taught courses for thousands
of developers and specializes in
making software engineering fun and
understandable.

informit.com/ph

Java_Rock_Star_CH_Openers.indd 2 6/18/09 11:42:16 AM


JavaFX.book Page 13 Monday, May 18, 2009 12:09 PM

2 A Taste of JavaFX

As the preface hints, JavaFX has a combination of features that makes it unique. This
chapter gives you a taste of the language and some of these features. Our goal is to
choose a representative example so you get a feel for the kinds of programs possible
with JavaFX. The example (a guitar tuner) illustrates language constructs while keep-
ing the discussion concrete. We’ll veer away from the example at times to illustrate
additional JavaFX features that are relevant. While this overview is in no way com-
plete (remember, it’s just a taste), we hope to entice you to explore JavaFX further.

The source code for GuitarTuner appears at the end of the chapter (see “Source Code
for Project GuitarTuner” on page 36). To keep the text flowing, we’ll show snippets
from this application throughout the overview.

What You Will Learn


• What makes JavaFX unique as a scripting language
• All about object literals and declarative constructs
• Introducing the JavaFX scene graph
• Declaring variables, properties, and objects
• Initializing objects and object properties
• Basics in container coordinate space and layout
• Creating a custom node
• Manipulating objects with color, effects, and gradients
• Getting things done with binding, event handlers, and animation

2.1 Introducing JavaFX


What is JavaFX? JavaFX is a scripting language with static typing. You can call a Java
API as needed from JavaFX and create new object types with classes, but JavaFX also
provides an easy declarative syntax. (Declarative means you say what you want and

13
JavaFX.book Page 14 Monday, May 18, 2009 12:09 PM

14 Chapter 2 A Taste of JavaFX

the system figures out how to do it for you.) JavaFX provides properties for manipu-
lating objects within a 2D coordinate system, specifying fill and pen stroke colors, and
creating special effects. You can create shapes and lines, manipulate images, play vid-
eos and sounds, and define animations.

Let’s begin exploring JavaFX by introducing the basics. Our introduction begins with
project GuitarTuner where you’ll see the main structure of a JavaFX program. Then,
you’ll explore a few JavaFX language constructs and see how to improve the appear-
ance of your applications. Finally, you’ll see how to make applications do things.

JavaFX in a Nutshell

JavaFX is statically typed, meaning program data types are known at compile time. JavaFX
also uses type inference. This means you don’t have to declare the type of every variable
because JavaFX can generally figure it out for you. This gives JavaFX the efficiency of a stati-
cally typed language combined with the ease of a declarative language.

2.2 Project GuitarTuner


Project GuitarTuner helps you tune your guitar. It displays a visual guitar fret board
with six strings. The letter (note) corresponding to the guitar string appears next to
the fret board. When you click a string with the mouse, you’ll hear a synthesized gui-
tar note for the selected string as it vibrates visually. Project GuitarTuner uses the Java
javax.sound.midi API to generate the sounds. Figure 2.1 shows this application run-
ning when the A string is vibrating. The corresponding JavaFX graphical objects are
labeled.

Rectangle (fret board)

GuitarString (6)

Line (2) (frets)

Figure 2.1 JavaFX application GuitarTuner


JavaFX.book Page 15 Monday, May 18, 2009 12:09 PM

Project GuitarTuner 15

The Scene Graph Metaphor


JavaFX programs with a graphical user interface define a stage and a scene within that
stage. The stage represents the top level container for all JavaFX objects; that is, the
content area for an applet or the frame for a widget. The central metaphor in JavaFX
for specifying graphics and user interaction is a scene graph. A scene defines a hierar-
chical node structure that contains all the scene’s components. Nodes are represented
by graphical objects, such as geometric shapes (Circle, Rectangle), text, UI controls,
image viewers, video viewers, and user-created objects (such as GuitarString in our
example). Nodes can also be containers that in turn hold more nodes, letting you
group nodes together in hierarchical structures. (For example, Group is a general-pur-
pose container node, HBox provides horizontal layout alignment, and VBox provides
vertical layout alignment.) The scene graph is this hierarchical node structure.

Figure 2.2 shows the scene graph for project GuitarTuner. Compare the visual graphi-
cal elements in Figure 2.1 with the scene graph depicted in Figure 2.2.

Scene
GuitarString
Group (CustomNode)

Rectangle Group
fret board
Rectangle
Line
(mouse detection)
frets
Line Rectangle
(normal)
GuitarString E string Rectangle

GuitarString (vibrating)
A string
. Text
. (note display)
.
GuitarString E string

Figure 2.2 Nested Scene Graph for GuitarTuner

In general, to construct a JavaFX application, you build the scene graph, specifying the
look and behavior of all its nodes. Then, your application just “runs.” Some applica-
tions need input to go—user actions that activate animations or affect component
JavaFX.book Page 16 Monday, May 18, 2009 12:09 PM

16 Chapter 2 A Taste of JavaFX

properties. Other applications just run on their own. (Building the scene graph is anal-
ogous to winding up a toy. When you’re done, the application just runs.)

JavaFX Scene Graph

The power of the scene graph is that, not only do you capture the entire structure of your appli-
cation in a data structure, but you can change the display simply by modifying properties of
the objects in the scene graph. (For example, if you change a node’s visible property to false,
that node, and any nodes it contains, disappears. If you change a node’s location, it moves.)

Within the scene graph for project GuitarTuner, you see the Scene at the top level,
which contains a Group. Within the Group there is a Rectangle for the fret board (the
guitar neck), two Line nodes representing frets, and six GuitarStrings. Each Guitar-
String is in turn its own Group consisting of three Rectangles and a Text node. Nodes
that contain other nodes (such as Scene and Group) include a content property that
holds subnodes. The hierarchical nature of the scene graph means that all nodes at the
same level share the same coordinate space. You therefore build node structures (such
as GuitarString) that use a relative coordinate system. You’ll see shortly why this is
useful.

Think Like A Designer

JavaFX encourages you to think like a designer. As a first step, visualize the structure of your
application or widget and compose your scene out of simple shapes and other building blocks.

The order of nodes within a parent container affects their rendering. That is, the first
node in the container is “drawn” first. The final node is “drawn” last and is on top of
the view. Nodes (depending on their placement within the coordinate system) may
visually block or “clip” previously drawn nodes. In GuitarTuner, the nodes must be in
a specific order. You draw the fret board first, then the frets, and finally the guitar
strings, which appear on top.

Changing the relative order of nodes in a container is easy. The toFront() function
brings a node to the front (top) and the toBack() function sends a node to the back
(bottom).

Hierarchical Scene Graph


Figure 2.3 also shows a scene graph of project GuitarTuner. Figure 2.2 and Figure 2.3
depict the same structure, but Figure 2.3 shows the hierarchical relationship among
the nodes in the scene using a graphical tree view. Nodes at the same level share the
same coordinate space. For example, the three Rectangles and Text nodes in the Gui-
tarString share the same coordinate system.
JavaFX.book Page 17 Monday, May 18, 2009 12:09 PM

JavaFX Program Structure 17

Scene

Group

Rectangle Line Line GuitarString GuitarString . . . GuitarString


(fret board) (frets) (E) (A) (E)

GuitarString (CustomNode)

Group

Rectangle Rectangle Rectangle Text

(mouse
detection) (normal) (vibrating) (note display)

Figure 2.3 Scene Node Graph for project GuitarTuner

2.3 JavaFX Program Structure


JavaFX program structure is simple. For programmers who are used to traditionally
compiled programs, programming in JavaFX will feel different. With static typing,
JavaFX gives you feedback at compile time when you use types incorrectly. This
greatly enhances your ability to write correct code. Furthermore, with the NetBeans
IDE, you can access JavaDocs for all JavaFX types (classes) and dynamically query
these class properties and functions, essentially getting feedback at edit time.

Let’s see how the Stage and Scene form the JavaFX program structure.

Stage and Scene


The Stage is the top-level container and contains the Scene. The Scene, in turn, holds
nodes that make up the scene graph. Every JavaFX program that has graphical objects
declares a Stage object.

Here is a top-level implementation of the scene graph for GuitarTuner from Figure 2.2
(or Figure 2.3). (We’ll look at GuitarString’s node graph shortly.)
JavaFX.book Page 18 Monday, May 18, 2009 12:09 PM

18 Chapter 2 A Taste of JavaFX

// Stage and Scene Graph


Stage {
title: "Guitar Tuner"
Scene {
// content is sequence of SceneGraph nodes
content: [
Group {
content: [
Rectangle { ... }
Line { ... }
Line { ... }
GuitarString { ... }
GuitarString { ... }
GuitarString { ... }
GuitarString { ... }
GuitarString { ... }
GuitarString { ... }
]
} // Group
]
} // Scene
} // Stage

Object Literals
The Stage and Scene objects are instantiated with object literal expressions, or object
literals. Object literals provide a declarative style of programming. Intuitively, declara-
tive means “tell me what you want, not how to do it.” As you will see, the real declar-
ative part of JavaFX is binding. We show why this is so powerful later in the chapter.

Object literals require an object (or class) type (such as Stage or Scene) followed by
curly braces { }. Any properties you need to initialize appear inside the braces. (Stage
has a title property and Scene and Group both have content properties.) Each prop-
erty has a name, followed by a colon : and an initial value for the property. You sep-
arate properties with commas, line breaks, or white space. Here, for example is an
object literal that initializes a Rectangle (properties x and y designate the upper-left
corner origin).
Rectangle { x: 10, y: 20, height: 15, width: 150 }

The above Stage, Scene, and Group objects are defined with object literals. Note that
the Scene object nests inside the Stage object. Likewise, a Group nests inside the
Scene. Square brackets [ ] define a sequence of items for the content property in a
Scene or Group. Here, the Scene object’s content property is a sequence of all of the
top-level nodes of the Scene. In the GuitarTuner application, this is a Group node (see
Figure 2.2 or Figure 2.3). The Group node likewise includes a content property with
all of its subnodes (Rectangles, Lines, and a custom GuitarString). How you nest these
nodes determines the structure of the scene graph.
JavaFX.book Page 19 Monday, May 18, 2009 12:09 PM

Key JavaFX Features 19

Here’s the top-level implementation for GuitarString from its scene graph in
Figure 2.2 (and Figure 2.3).
// GuitarString - defined as custom class
Group {
content: [
Rectangle { ... }
Rectangle { ... }
Rectangle { ... }
Text { ... }
]
} // Group

The GuitarString consists of a Group node whose content property defines a sequence
containing three rectangles and a Text object. You’ll see how this fits into the Guitar-
Tuner application later on.

2.4 Key JavaFX Features


GuitarTuner is a fairly typical JavaFX example application. It has a graphical repre-
sentation and responds to user input by changing some of its visual properties (as
well as producing guitar sounds). Let’s look at some of the key JavaFX features it uses
to give you a broad look at the language.

Signature JavaFX Features

Included in any list of key JavaFX features are binding, node event handlers, and animation.
We discuss each of these important constructs in their own section (see “Doing Things” on
page 31).

Type Inference
JavaFX provides def for read-only variables and var for modifiable variables.
def numberFrets = 2; // read-only Integer
var x = 27.5; // variable Number
var y: Number; // default value is 0.0
var s: String; // default value is ""

The compiler infers types from the values you assign to variables. Read-only number-
Frets has inferred type Integer; variable x has inferred type Number (Float). This
means you don’t have to specify types everywhere (and the compiler tells you when a
type is required.)
JavaFX.book Page 20 Monday, May 18, 2009 12:09 PM

20 Chapter 2 A Taste of JavaFX

Strings
JavaFX supports dynamic string building. Curly braces { } within a String expression
evaluate to the contents of the enclosed variable. You can build Strings by concatenat-
ing these String expressions and String literals. For example, the following snippet
prints "Greetings, John Doe!".
def s1 = "John Doe";
println("Greetings, {s1}!"); // Greetings, John Doe!

Shapes
JavaFX has numerous shapes that help you create scene graph nodes. There are
shapes for creating lines (Line, CubicCurve, QuadCurve, PolyLine, Path) and shapes
for creating geometric figures (Arc, Circle, Ellipse, Rectangle, Polygon). The Guitar-
Tuner application uses only Rectangle and Line, but you’ll see other shape examples
throughout this book.

Let’s look at shapes Rectangle and Circle. They are both standard JavaFX shapes that
extend class Shape (in package javafx.scene.shape). You define a Circle by specifying
values for its radius, centerX, and centerY properties. With Rectangle, you specify val-
ues for properties height, width, x, and y.

Shapes share several properties in common, including properties fill (type Paint to
fill the interior of the shape), stroke (type Paint to provide the outline of the shape),
and strokeWidth (an Integer for the width of the outline).

Here, for example, is a Circle with its center at point (50,50), radius 30, and color
Color.RED.
Circle {
radius: 30
centerX: 50
centerY: 50
fill: Color.RED
}

Here is a Rectangle with its top left corner at point (30, 100), height 30, width 80, and
color Color.BLUE.
Rectangle {
x: 30, y: 100
height: 30, width: 80
fill: Color.BLUE
}

All shapes are also Nodes (javafx.scene.Node). Node is an all-important class that
provides local geometry for node elements, properties to specify transformations
JavaFX.book Page 21 Monday, May 18, 2009 12:09 PM

Key JavaFX Features 21

(such as translation, rotation, scaling, or shearing), and properties to specify functions


for mouse and key events. Nodes also have properties that let you assign CSS styles to
specify rendering.1 We discuss graphical objects in detail in Chapter 4.

Sequences
Sequences let you define a collection of objects that you can access sequentially. You
must declare the type of object a sequence will hold or provide values so that its type
can be inferred. For example, the following statements define sequence variables of
GuitarString and Rectangle objects.
var guitarStrings: GuitarString[];
var rectangleSequence: Rectangle[];

These statements create read-only sequences with def. Here, sequence noteValues has
an inferred type of Integer[]; sequence guitarNotes has an inferred type of String[].
def noteValues = [ 40,45,50,55,59,64 ];
def guitarNotes = [ "E","A","D","G","B","E" ];

Sequences have specialized operators and syntax. You will use sequences in JavaFX
whenever you need to keep track of multiple items of the same object type. The
GuitarTuner application uses a sequence with a for loop to build multiple Line objects
(the frets) and GuitarString objects.
// Build Frets
for (i in [0..<numberFrets])
Line { . . . }

// Build Strings
for (i in [0..<numberStrings])
GuitarString { . . . }

The notation [0..<n] is a sequence literal and defines a range of numbers from 0 to
n-1, inclusive.

You can declare and populate sequences easily. The following declarative approach
inserts Rectangles into a sequence called rectangleSequence, stacking six Rectangles
vertically.
def rectangleSequence = for (i in [0..5])
Rectangle {

1. Cascading Style Sheets (CSS) help style web pages and let designers give a uniform look and
feel throughout an application, widget, or entire web site. You can use CSS to similarly style
JavaFX nodes. (See “Cascading Style Sheets (CSS)” on page 148 for details on applying styles
to JavaFX nodes.)
JavaFX.book Page 22 Monday, May 18, 2009 12:09 PM

22 Chapter 2 A Taste of JavaFX

x: 20
y: i * 30
height: 20
width: 40
}

You can also insert number values or objects into an existing sequence using the
insert operator. The following imperative approach inserts the six Rectangles into a
sequence called varRectangleSequence.
var varRectangleSequence: Rectangle[];
for (i in [0..5])
insert Rectangle {
x: 20
y: i * 30
height: 20
width: 40
} into varRectangleSequence;

JavaFX Tip

The declarative approach with rectangleSequence is always preferred (if possible). By using
def rather than var and declaring sequences rather than inserting objects into them, type
inference will more likely help you and the compiler can optimize the code more effectively.

You’ll see more uses of sequence types throughout this book.

Calling Java APIs


You can call any Java API method in JavaFX programs without having to do anything
special. The GuitarString node “plays a note” by calling function noteOn found in Java
class SingleNote. Here is GuitarString function playNote which invokes SingleNote
member function noteOn.
function playNote(): Void {
synthNote.noteOn(note); // nothing special to call Java methods
vibrateOn();
}

Class SingleNote uses the Java javax.sound.midi package to generate a synthesized


note with a certain value (60 is “middle C”). Java class SingleNote is part of project
GuitarTuner.

Extending CustomNode
JavaFX offers developers such object-oriented features as user-defined classes, over-
riding virtual functions, and abstract base classes (there is also “mixin” inheritance).
JavaFX.book Page 23 Monday, May 18, 2009 12:09 PM

Key JavaFX Features 23

GuitarTuner uses a class hierarchy with subclass GuitarString inheriting from a


JavaFX class called CustomNode, as shown in Figure 2.4.

Extensible scene
CustomNode graph node

Encapsulates
GuitarString graphical structure
and behavior of
GuitarString node

Figure 2.4 GuitarString Class Hierarchy

This approach lets you build your own graphical objects. In order for a custom object
to fit seamlessly into a JavaFX scene graph, you base its behavior on a special class
provided by JavaFX, CustomNode. Class CustomNode is a scene graph node (a type of
Node, discussed earlier) that lets you specify new classes that extend from it. Just like
Java, “extends” is the JavaFX language construct that creates an inheritance relation-
ship. Here, GuitarString extends (inherits from) CustomNode. You then supply the
additional structure and behavior you need for GuitarString objects and override any
functions required by CustomNode. JavaFX class constructs are discussed in more
detail in Chapter 3 (see “Classes and Objects” on page 67).

Here is some of the code from GuitarTuner's GuitarString class. The create function
returns a Node defining the Group scene graph for GuitarString. (This scene graph
matches the node structure in Figure 2.2 on page 15 and Figure 2.3 on page 17.
Listing 2.2 on page 38 shows the create function in more detail.)
public class GuitarString extends CustomNode {
// properties, variables, functions
. . .
protected override function create(): Node {
return Group {
content: [
Rectangle { ... }
Rectangle { ... }
Rectangle { ... }
Text { ... }
]
} // Group
}
} // GuitarString
JavaFX.book Page 24 Monday, May 18, 2009 12:09 PM

24 Chapter 2 A Taste of JavaFX

Geometry System
In JavaFX, nodes are positioned on a two-dimensional coordinate system with the ori-
gin at the upper-left corner. Values for x increase horizontally from left to right and y
values increase vertically from top to bottom. The coordinate system is always relative
to the parent container.

Layout/Groups
Layout components specify how you want objects drawn relative to other objects. For
example, layout component HBox (horizontal box) evenly spaces its subnodes in a
single row. Layout component VBox (vertical box) evenly spaces its subnodes in a sin-
gle column. Other layout choices are Flow, Tile, and Stack (see “Layout Components”
on page 119). You can nest layout components as needed.

Grouping nodes into a single entity makes it straightforward to control event han-
dling, animation, group-level properties, and layout for the group as a whole. Each
group (or layout node) defines a coordinate system that is used by all of its children.
In GuitarTuner, the top level node in the scene graph is a Group which is centered ver-
tically within the scene. The subnodes are all drawn relative to the origin (0,0) within
the top-level Group. Centering the Group, therefore, centers its contents as a whole.

Benefits of Relative Coordinate Space

Nodes with the same parent share the same relative coordinate space. This keeps any coordinate
space calculations for subnodes separate from layout issues of the parent container. Then, when
you move the parent, everything under it moves, keeping relative positions intact.

JavaFX Script Artifacts


Defining the Stage and Scene are central to most JavaFX applications. However,
JavaFX scripts can also contain package declarations, import statements, class declara-
tions, functions, variable declarations, statements, and object literal expressions.
You’ve already seen how object literal expressions can initialize nodes in a scene
graph. Let’s discuss briefly how you can use these other artifacts.

Since JavaFX is statically typed, you must use either import statements or declare all
types that are not built-in. You’ll typically define a package and then specify import
statements. (We discuss working with packages in Chapter 3. See “Script Files and
Packages” on page 86.) Here is the package declaration and import statements for
GuitarTuner.
package guitartuner;

import javafx.scene.effect.DropShadow;
JavaFX.book Page 25 Monday, May 18, 2009 12:09 PM

Key JavaFX Features 25

import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;

. . . more import statements . . .

import javafx.stage.Stage;
import noteplayer.SingleNote;

If you’re using NetBeans, the IDE can generate import statements for you (type
Ctrl+Shift+I in the editor window).

You’ll need script-level variables to store data and read-only variables (def ) for values
that don’t change. In GuitarTuner, we define several read-only variables that help
build the guitar strings and a variable (singleNote) that communicates with the Java
midi API. Note that noteValues and guitarNotes are def sequence types.
def noteValues = [ 40,45,50,55,59,64 ];
def guitarNotes = [ "E","A","D","G","B","E" ];
def numberFrets = 2;
def numberStrings = 6;
var singleNote = SingleNote { };

When you declare a Stage, you define the nested nodes in the scene graph. Instead of
declaring nodes only as object literal expressions, it’s also possible to assign these
object literals to variables. This lets you refer to them later in your code. (For example,
the Scene object literal and the Group object literal are assigned to variables in order
to compute the offset for centering the group vertically in the scene.)
var scene: Scene;
var group: Group;

scene: scene = Scene { ... }


group = Group { ... }

You may also need to execute JavaFX script statements or define utility functions.
Here’s how GuitarTuner makes the SingleNote object emit a “guitar” sound.
singleNote.setInstrument(27); // "Clean Guitar"

Once you set up the Stage and scene graph for an application, it’s ready to ready to
run.2 In GuitarTuner, the application waits for the user to pluck (click) a guitar string.

2. Java developers may wonder where function main() is. As it turns out, the JavaFX compiler
generates a main() for you, but from a developer’s view, you have just a script file.
JavaFX.book Page 26 Monday, May 18, 2009 12:09 PM

26 Chapter 2 A Taste of JavaFX

2.5 Making Things Look Good


Using JavaFX features that enhance the appearance of graphical objects will help your
application look professionally designed. Here are some simple additions you can
apply.

Gradients
Gradients lend a depth to surfaces and backgrounds by gradually varying the color of
the object’s fill property. In general, use linear gradients with rectangular shapes and
radial gradients with circles and ovals. In GuitarTuner, the background is a linear gra-
dient that transitions from Color.LIGHTGRAY (at the top) to the darker Color.GRAY (at
the bottom) as shown in Figure 2.5. The guitar fret board also uses a linear gradient.

Fret Board
Linear
Gradient

Background
Linear
Gradient

Figure 2.5 Gradients in the GuitarTuner Application

Here is the LinearGradient for the background scene in GuitarTuner, defined for
property fill. Note that specifying gradients is declarative; you identify the look you
want and the system figures out how to achieve it, independent of screen resolution,
color depth, etc.
fill: LinearGradient {
startX: 0.0
startY: 0.0
endX: 0.0
endY: 1.0
proportional: true
stops: [
Stop {
offset: 0.0
color: Color.LIGHTGRAY
},
Stop {
offset: 1.0
JavaFX.book Page 27 Monday, May 18, 2009 12:09 PM

Making Things Look Good 27

color: Color.GRAY
}
]
}

The background gradient changes color along the y axis and the color is constant
along the x axis (properties startX and endX are the same). Property stops is a
sequence of Stop objects containing an offset and a color. The offset is a value
between 0 and 1 inclusive; each succeeding offset must have a higher value than the
preceding one.

Property proportional indicates whether start and end values are proportional
(defined between [0..1] if true) or absolute (absolute coordinates if false).

Radial gradients work well for circular shapes, as shown in Figure 2.6. Here you see
three Circle shapes, all with radial gradients. The first circle defines a gradient with its
center in the lower left quadrant (centerX is 0.25 and centerY is 0.75). The second cir-
cle’s gradient is centered (centerX and centerY are both 0.5), and the third circle’s gra-
dient appears in the upper right quadrant (centerX is 0.75 and centerY is 0.25).

Figure 2.6 Radial Gradients work well with circular shapes

Here is the radial gradient for the middle circle.

fill: RadialGradient {
centerX: 0.5 // x center of gradient
centerY: 0.5 // y center of gradient
radius: 0.5 // radius of gradient
stops: [
Stop {
offset: 0
color: Color.WHITE
},
Stop {
offset: 1
JavaFX.book Page 28 Monday, May 18, 2009 12:09 PM

28 Chapter 2 A Taste of JavaFX

color: Color.DODGERBLUE
}
]
}

Note that the gradient is half the size of the circle (radius is 0.5). Making the gradient
less than the full size lets the last stop color appear more prominent (the dark color
predominates).

Color
You specify a shape’s color with property fill. JavaFX has many predefined colors
ranging alphabetically from Color.ALICEBLUE to Color.YELLOWGREEN. (In the NetBeans
IDE, press Ctrl+Space when the cursor is after the dot in Color to see a complete list,
as shown in Figure 2.7.)

Figure 2.7 Explore color choices with the NetBeans IDE

You can also specify arbitrary colors with Color.rgb (each RGB value ranges from 0 to
255), Color.color (each RGB value ranges from 0 to 1), and Color.web (a String corre-
sponding to the traditional hexadecimal-based triad). An optional final argument sets
the opacity, where 1 is fully opaque and 0 is fully translucent. You can also make a
shape transparent by setting its fill property to Color.TRANSPARENT.

Here are several examples of color settings. Each example sets the opacity to .5, which
allows some of the background color to show through.
def c1 = Color.rgb(10, 255, 15, .5); // bright lime green
def c2 = Color.color(0.5, 0.1, 0.1, .5); // dark red
def c3 = Color.web("#546270", .5); // dark blue-gray
JavaFX.book Page 29 Monday, May 18, 2009 12:09 PM

Making Things Look Good 29

Numeric-based color values (rather than hexadecimal strings or predefined colors) let
you write functions and animations that numerically manipulate gradients, colors, or
opacity. For example, the following fill property gets its Color.rgb values from a for
loop’s changing value i. The loop produces three different shades of green, depending
on the value of i.
def rectangleSequence = for (i in [0..2])
Rectangle {
x: 60 * i
y: 50
height: 50
width: 40
fill: Color.rgb(10 + (i*50), 100 + (i*40), i*50)
}

Figure 2.8 shows the resulting set of rectangles with different fill values.

Figure 2.8 Manipulating numeric-based Color values

Rectangles with Arcs


You can soften the corners of Rectangles by specifying properties arcWidth and
arcHeight, as shown in Figure 2.9. The first Rectangle has regular, square corners. The
second Rectangle sets arcHeight and arcWidth to 15, and the third one uses value 30
for both. Here’s the object literal for the third Rectangle.

Rectangle {
x: 180
y: 0
height: 70
width: 60
arcHeight: 30
arcWidth: 30
fill: LinearGradient { . . . }
}
JavaFX.book Page 30 Monday, May 18, 2009 12:09 PM

30 Chapter 2 A Taste of JavaFX

Figure 2.9 Soften Rectangles with rounded corners

DropShadows
One of the many effects you can specify is DropShadow (effects are declarative).
Effect DropShadow applies a shadow to its node, giving the node a three-dimensional
look. In project GuitarTuner, the fret board (guitar neck) uses a default drop shadow,
as follows.
effect: DropShadow { }

The default object literal provides a drop shadow with these values.
effect: DropShadow {
offsetX: 0.0
offsetY: 0.0
radius: 10.0
color: Color.BLACK
spread: 0.0
}

You can manipulate the location of the shadow by changing offsetX and offsetY.
Negative values for offsetY set the shadow above the object and negative values for
offsetX set the shadow to the left. Positive values for offsetX and offsetY place the
shadow to the right and below, respectively. You can also change a shadow’s size
(radius), color, and spread (how “sharp” the shadow appears). A spread value of 1
means the shadow is sharply delineated. A value of 0 provides a “fuzzy” appearance.
Figure 2.10 shows three rectangles with drop shadows that fall below and to the right
of the rectangles, using these offsets.
effect: DropShadow {
// shadow appears below and to the right of object
offsetX: 5.0
offsetY: 5.0
}
JavaFX.book Page 31 Monday, May 18, 2009 12:09 PM

Doing Things 31

Figure 2.10 Drop shadows provide a three-dimensional effect

2.6 Doing Things


JavaFX has three main constructs for doing things: binding, node properties that
define event handlers, and animation. Together, these constructs provide powerful yet
elegant solutions for modifying scene graphs based on user input or other events.
Let’s see how GuitarTuner uses these constructs to get its tasks done.

Binding
Binding in JavaFX is a powerful technique and a concise alternative to specifying tra-
ditional callback event handlers. Basically, binding lets you make a property or vari-
able depend on the value of an expression. When you update any of the “bound to”
objects in the expression, the dependent object automatically changes. Suppose, for
example, we bind area to height and width, as follows.
var height = 3.0;
var width = 4.0;
def area = bind height * width; // area = 12.0

width = 2.5; // area = 7.5


height = 4; // area = 10.0

When either height or width changes, so does area. Once you bind a property (or vari-
able), you can’t update it directly. For example, you get a compile-time error if you try
to directly update area.
area = 5; // compile time error

If you make area a var and provide a binding expression, you’ll get a runtime error if
you try to update it directly.
JavaFX.book Page 32 Monday, May 18, 2009 12:09 PM

32 Chapter 2 A Taste of JavaFX

In GuitarTuner, the vibrating string changes both its location (property translateY)
and its thickness (property height) at run time to give the appearance of vibration.
These properties are bound to other values that control how a guitar string node
changes.
var vibrateH: Number;
var vibrateY: Number;

Rectangle {
x: 0.0
y: yOffset
width: stringLength
height: bind vibrateH // change height when vibrateH changes
fill: stringColor
visible: false
translateY: bind vibrateY // change translateY when vibrateY changes
}

GuitarTuner also uses bind to keep the fret board centered vertically by binding prop-
erty layoutY in the top level group.
group = Group {
layoutY: bind (scene.height - group.layoutBounds.height) /
2 - group.layoutBounds.minY
. . .
}

Node property layoutBounds provides bounds information for its contents. If a user
resizes the window, the top level group is automatically centered vertically on the
screen. Binding helps reduce event processing code because (here, for example) you
don’t have to write an event handler to detect a change in the window size.

Binding is Good

Binding is good for many things. For example, you can change the appearance of a node based
on changes to the program’s state. You can make a component visible or hidden. You can also
use binding to declaratively specify layout constraints. Not only does binding produce less
code, but the code is less error-prone, easier to maintain, and often easier for the compiler to
optimize.

Mouse Events
JavaFX nodes have properties for handling mouse and key events. These properties
are set to callback functions that the system invokes when an event triggers. In Guitar-
Tuner, the “mouse detection” rectangle has the following event handler to detect a
mouse click event.
JavaFX.book Page 33 Monday, May 18, 2009 12:09 PM

Doing Things 33

onMouseClicked: function(evt: MouseEvent): Void {


if (evt.button == MouseButton.PRIMARY) {
// play and vibrate selected “string”
}
}

The if statement checks for a click of the primary mouse button (generally the left
mouse button is primary) before processing the event. The event handler function
(shown in the next section) plays the note and vibrates the string.

Animations
JavaFX specializes in animations. (In fact, we dedicate an entire chapter to animation.
See Chapter 7 beginning on page 205.) You define animations with timelines and then
invoke Timeline functions play or playFromStart (there are also functions pause and
stop). Timelines consist of a sequence of key frame objects that define a frame at a spe-
cific time offset within the timeline. (Key frames are declarative. You say “this is the
state of the scene at this key time” and let the system figure out how to render the
affected objects.) Within each key frame, you specify values, an action, or both. Tradi-
tionally, people think of animations as a way to move objects. While this is true, you’ll
see that JavaFX lets you animate any writable object property. You could, for instance,
use animation to fade, rotate, resize, or even brighten an image.

Figure 2.11 shows a snapshot of a program with simple animation. It moves a circle
back and forth across its container.

Figure 2.11 Timelines let you specify animations

Here is the timeline that implements this animation using a specialized shorthand
notation for KeyFrames. The timeline starts out by setting variable x to 0. In gradual,
linear increments, it changes x so that at four seconds, its value is 350. Now, it per-
forms the action in reverse, gradually changing x so that in four more seconds it is
back to 0 (autoReverse is true). This action is repeated indefinitely (or until the time-
line is stopped or paused). Constants 0s and 4s are Duration literals.
JavaFX.book Page 34 Monday, May 18, 2009 12:09 PM

34 Chapter 2 A Taste of JavaFX

var x: Number;
Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at (0s) { x => 0.0 }
at (4s) { x => 350 tween Interpolator.LINEAR }
]
}.play(); // start Timeline
. . .
Circle {
. . .
translateX: bind x
}

The JavaFX keyword tween is a key frame operator that lets you specify how a variable
changes. Here, we use Interpolator.LINEAR for a linear change. That is, x doesn’t
jump from 0 to 350, but gradually takes on values in a linear fashion. Linear interpola-
tion moves the Circle smoothly from 0 to 350, taking four seconds to complete one
iteration of the timeline.

JavaFX has other interpolators. Interpolator DISCRETE jumps from the value of one key
frame to the second. Interpolator EASEIN is similar to LINEAR, except the rate of change
is slower at the onset. Similarly, EASEOUT is slower at the finish and EASEBOTH provides
easing on both ends of the timeline.

To make this animation apply to the Circle node, you bind the Circle’s translateX
property to the variable manipulated by the timeline (x). Property translateX repre-
sents a node’s change in the x direction.

Now let’s examine how GuitarTuner uses animation to vibrate the guitar string and
play its note. Each GuitarString object uses two rectangles to implement its visible
behavior. One rectangle is a stationary, thin “string” and represents the string in a
static state. This motionless rectangle is always visible in the scene. The second rectan-
gle is only visible when the string is “played.” This rectangle expands and contracts
its height quickly using animation (a Timeline). This moving rectangle gives users the
illusion of a vibrating string.

To get a uniform vibrating effect, the rectangle must expand and contract evenly on
the top and bottom. The animation makes the string appear to vibrate by varying the
height of the rectangle from 1 to 3 while keeping it vertically centered by varying its
translateY property between 5 and 4. When the string is clicked, the string’s note
plays and the rectangle vibrates for the allotted time. When the timeline stops, only
the stationary rectangle is visible.
JavaFX.book Page 35 Monday, May 18, 2009 12:09 PM

Doing Things 35

Let’s first look at the timeline that plays the note. This timeline appears in the event
handler for the GuitarString node (see the code for GuitarString in Listing 2.2 on
page 38).
onMouseClicked: function(evt: MouseEvent): Void {
if (evt.button == MouseButton.PRIMARY) {
Timeline {
keyFrames: [
KeyFrame {
time: 0s
action: playNote // play note and start vibration
}
KeyFrame {
time: 2.8s
action: stopNote // stop playing note and stop vibration
}
]
}.play(); // start Timeline
}
}

Here, the timeline is an object literal defined inside the event handler, invoked with
function play. This timeline defines a sequence of KeyFrame objects, where function
playNote is invoked at time offset 0 seconds and function stopNote is invoked at time
offset 2.8 seconds (2.8s). Here are functions playNote and stopNote.
// play note and start vibration
function playNote(): Void {
synthNote.noteOn(note);
vibrateOn();
}

// stop playing note and stop vibration


function stopNote(): Void {
synthNote.noteOff(note);
vibrateOff();
}

Function synthNote.noteOn calls a Java class API to play the guitar string. Function
vibrateOn causes the string vibration.
function vibrateOn(): Void {
play.visible = true; // make the vibrating rectangle visible
timeline.play(); // start the vibration timeline
}

Here is the vibration timeline.


def timeline = Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
JavaFX.book Page 36 Monday, May 18, 2009 12:09 PM

36 Chapter 2 A Taste of JavaFX

at (0s) { vibrateH => 1.0 }


at (.01s) { vibrateH => 3.0 tween Interpolator.LINEAR }
at (0s) { vibrateY => 5.0 }
at (.01s) { vibrateY => 4.0 tween Interpolator.LINEAR }
]
};

This timeline uses the shorthand notation discussed earlier for key frames and ani-
mates two variables: vibrateH and vibrateY. Variable vibrateH changes the height of
the rectangle that represents the vibrating string. Variable vibrateY changes the verti-
cal position of the rectangle to keep it centered as the oscillating height changes.

2.7 Source Code for Project GuitarTuner


Listing 2.1 and Listing 2.2 show the code for class GuitarString in two parts.
Listing 2.1 includes the class declarations, functions, class-level variables, and proper-
ties for class GuitarString. Note that several variables are declared public-init. This
JavaFX keyword means that users of the class can provide initial values with object lit-
erals, but otherwise these properties are read-only. The default accessibility for all
variables is script-private, making the remaining declarations private.

Use def for read-only variables and var for modifiable variables. The GuitarString
class also provides utility functions that play a note (playNote) or stop playing a note
(stopNote). Along with the sound, guitar strings vibrate on and off with vibrateOn and
vibrateOff. These functions implement the behavior of the GuitarString class.

Listing 2.1 Class GuitarString—Properties, Variables, and Functions


package guitartuner;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Cursor;
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import noteplayer.SingleNote;

public class GuitarString extends CustomNode {


JavaFX.book Page 37 Monday, May 18, 2009 12:09 PM

Source Code for Project GuitarTuner 37

// read-only variables
def stringColor = Color.WHITESMOKE;
// "Strings" are oriented sideways, so stringLength is the
// Rectangle width and stringSize is the Rectangle height
def stringLength = 300;
def stringSize = 1;
def stringMouseSize = 15;
def timeline = Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at (0s) { vibrateH => 1.0 }
at (.01s) { vibrateH => 3.0 tween Interpolator.LINEAR }
at (0s) { vibrateY => 5.0 }
at (.01s) { vibrateY => 4.0 tween Interpolator.LINEAR }
]
};

// properties to be initialized
public-init var synthNote: SingleNote;
public-init var note: Integer;
public-init var yOffset: Number;
public-init var noteText: String;

// class variables
var vibrateH: Number;
var vibrateY: Number;
var play: Rectangle;

function vibrateOn(): Void {


play.visible = true;
timeline.play();
}
function vibrateOff(): Void {
play.visible = false;
timeline.stop();
}
function playNote(): Void {
synthNote.noteOn(note);
vibrateOn();
}
function stopNote(): Void {
synthNote.noteOff(note);
vibrateOff();
}
JavaFX.book Page 38 Monday, May 18, 2009 12:09 PM

38 Chapter 2 A Taste of JavaFX

Listing 2.2 shows the second part of the code for the GuitarString class.

Every class that extends CustomNode must define a function create that returns a
Node object.3 Often the node you return will be a Group, since Group is the most gen-
eral Node type and can include subnodes. But, you can return other Node types, such
as Rectangle (Shape) or HBox (horizontal box) layout node.

The scene graph for GuitarString is interesting because it actually consists of three
Rectangle nodes and a Text node. The first Rectangle, used to detect mouse clicks, is
completely translucent (its opacity is 0). This Rectangle is wider than the guitar string
so the user can more easily select it with the mouse. Several properties implement its
behavior: property cursor lets a user know the string is selected and property
onMouseClicked provides the event handling code (play the note and vibrate the
string).

The second Rectangle node defines the visible string. The third Rectangle node
(assigned to variable play) “vibrates” by both moving and changing its height. This
rectangle is only visible when a note is playing and provides the vibration effect of
“plucking” a string. The movement and change in height are achieved with animation
and binding. The Text node simply displays the letter (E, A, D, etc.) associated with
the guitar string’s note.

Listing 2.2 Scene Graph for GuitarString

protected override function create(): Node {


return Group {
content: [
// Rectangle to detect mouse events for string plucking
Rectangle {
x: 0
y: yOffset
width: stringLength
height: stringMouseSize
// Rectangle has to be "visible" or scene graph will
// ignore mouse events. Therefore, we make it fully
// translucent (opacity=0) so it is effectively invisible
fill: Color.web("#FFFFF", 0) // translucent
cursor: Cursor.HAND
onMouseClicked: function(evt: MouseEvent): Void {
if (evt.button == MouseButton.PRIMARY){
Timeline {
keyFrames: [
KeyFrame {

3. Well, almost. If you don’t define function create, then you must declare the class abstract.
The Piano example (see “Project Piano” on page 167) uses an abstract class.
JavaFX.book Page 39 Monday, May 18, 2009 12:09 PM

Source Code for Project GuitarTuner 39

time: 0s
action: playNote
}
KeyFrame {
time: 2.8s
action: stopNote
}
] // keyFrames

}.play(); // start Timeline


} // if
}
} // Rectangle
// Rectangle to render the guitar string
Rectangle {
x: 0.0
y: 5 + yOffset
width: stringLength
height: stringSize
fill: stringColor
}
// Special "string" that vibrates by changing its height
// and location
play = Rectangle {
x: 0.0
y: yOffset
width: stringLength
height: bind vibrateH
fill: stringColor
visible: false
translateY: bind vibrateY
}
Text { // Display guitar string note name
x: stringLength + 8
y: 13 + yOffset
font: Font {
size: 20
}
content: noteText
}
]
} // Group
}
} // GuitarString

Listing 2.3 shows the code for Main.fx, the main program for GuitarTuner.
JavaFX.book Page 40 Monday, May 18, 2009 12:09 PM

40 Chapter 2 A Taste of JavaFX

Listing 2.3 Main.fx


package guitartuner;
import guitartuner.GuitarString;
import javafx.scene.effect.DropShadow;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.Scene;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import noteplayer.SingleNote;

def noteValues = [ 40,45,50,55,59,64 ]; // numeric value required by midi


def guitarNotes = [ "E","A","D","G","B","E" ];
// guitar note name
def numberFrets = 2;
def numberStrings = 6;
var singleNote = SingleNote{};
singleNote.setInstrument(27); // "Clean Guitar"

var scene: Scene;


var group: Group;
Stage {
title: "Guitar Tuner"
visible: true
scene: scene = Scene {
fill: LinearGradient {
startX: 0.0
startY: 0.0
endX: 0.0
endY: 1.0
proportional: true
stops: [
Stop {
offset: 0.0
color: Color.LIGHTGRAY
},
Stop {
offset: 1.0
color: Color.GRAY
}
]
}
width: 340
height: 200
content: [
group = Group {
// Center the whole group vertically within the scene
layoutY: bind (scene.height - group.layoutBounds.height) /
JavaFX.book Page 41 Monday, May 18, 2009 12:09 PM

Source Code for Project GuitarTuner 41

2 - group.layoutBounds.minY
content: [
Rectangle { // guitar neck (fret board)
effect: DropShadow { }
x: 0
y: 0
width: 300
height: 121
fill: LinearGradient {
startX: 0.0
startY: 0.0
endX: 0.0
endY: 1.0
proportional: true
stops: [
Stop {
offset: 0.0
color: Color.SADDLEBROWN
},
Stop {
offset: 1.0
color: Color.BLACK
}
]
}
} // Rectangle
for (i in [0..<numberFrets]) // two frets
Line {
startX: 100 * (i + 1)
startY: 0
endX: 100 * (i + 1)
endY: 120
stroke: Color.GRAY
}
for (i in [0..<numberStrings]) // six guitar strings
GuitarString {
yOffset: i * 20 + 5
note: noteValues[i]
noteText: guitarNotes[i]
synthNote: singleNote
}
]
}
]
}
}
Google
Bookmarks Delicious Digg Facebook StumbleUpon Reddit Twitter

Java_Rock_Star_CH_Openers copy.indd 5 6/18/09 11:47:01 AM


Joshua Bloch
Neal Gafter

Java™ Puzzlers: Traps, Pitfalls,


and Corner Cases
How well do you really know Java? Are you a code sleuth? Have you ever spent days
chasing a bug caused by a trap or pitfall in Java or its libraries? Do you like brainteas- AVAILABLE
ers? Then this is the book for you!
• BOOK: 9780321336781
In the tradition of Effective Java™, Bloch and Gafter dive deep into the subtleties of • SAFARI ONLINE
the Java programming language and its core libraries. Illustrated with visually stunning • EBOOK: 032164350X
optical illusions, Java™ Puzzlers features 95 diabolical puzzles that educate and • KINDLE: 0321643518
entertain. Anyone with a working knowledge of Java will understand the puzzles, but
even the most seasoned veteran will find them challenging.
Most of the puzzles take the form of a short program whose behavior isn’t what it seems.
About the Authors
Can you figure out what it does? Puzzles are grouped loosely according to the features Joshua Bloch is a principal engineer
they use, and detailed solutions follow each puzzle. The solutions go well beyond a at Google and a Jolt Award-winner.
simple explanation of the program’s behavior--they show you how to avoid the underly- He was previously a distinguished
ing traps and pitfalls for good. A handy catalog of traps and pitfalls at the back of the engineer at Sun Microsystems and a
book provides a concise taxonomy for future reference. senior systems designer at Transarc.
Solve these puzzles and you’ll never again fall prey to the counterintuitive or obscure Josh led the design and implemen-
behaviors that can fool even the most experienced programmers. tation of numerous Java platform
features, including JDK 5.0 language
enhancements and the award-winning
Java Collections Framework. He holds
a Ph.D. in computer science from
Carnegie Mellon University.
Neal Gafter is a software engineer
and Java evangelist at Google. He was
previously a senior staff engineer at
Sun Microsystems, where he led the
development of the Java compiler and
implemented the Java language fea-
tures in releases 1.4 through 5.0. Neal
was a member of the C++ Standards
Committee and led the develop-
ment of C and C++ compilers at Sun
Microsystems, Microtec Research, and
Texas Instruments. He holds a Ph.D. in
computer science from the University
of Rochester.

informit.com/aw

Java_Rock_Star_CH_Openers copy.indd 6 6/18/09 11:47:02 AM


puzzlers.book Page 25 Thursday, June 9, 2005 10:37 PM

Puzzlers with Character


3
This chapter contains puzzles that concern strings, characters, and other textual
data.

Puzzle 11: The Last Laugh


What does the following program print?

public class LastLaugh {


public static void main(String args[]) {
System.out.print("H" + "a");
System.out.print(’H’ + ’a’);
}
}

25
puzzlers.book Page 26 Thursday, June 9, 2005 10:37 PM

26 Chapter 3 • Puzzlers with Character

Solution 11: The Last Laugh


If you are like most people, you thought that the program would print HaHa. It looks
as though it concatenates H to a in two ways, but looks can be deceiving. If you ran
the program, you found that it prints Ha169. Now why would it do a thing like that?
As expected, the first call to System.out.print prints Ha: Its argument is the
expression "H" + "a", which performs the obvious string concatenation. The sec-
ond call to System.out.print is another story. Its argument is the expression
’H’ + ’a’. The problem is that ’H’ and ’a’ are char literals. Because neither
operand is of type String, the + operator performs addition rather than string con-
catenation.
The compiler evaluates the constant expression ’H’ + ’a’ by promoting each
of the char-valued operands (’H’ and ’a’) to int values through a process known
as widening primitive conversion [JLS 5.1.2, 5.6.2]. Widening primitive conver-
sion of a char to an int zero extends the 16-bit char value to fill the 32-bit int. In
the case of ’H’, the char value is 72 and in the case of ’a’, it is 97, so the expres-
sion ’H’ + ’a’ is equivalent to the int constant 72 + 97, or 169.
From a linguistic standpoint, the resemblance between char values and
strings is illusory. As far as the language is concerned, a char is an unsigned 16-
bit primitive integer—nothing more. Not so for the libraries. They contain many
methods that take char arguments and treat them as Unicode characters.
So how do you concatenate characters? You could use the libraries. For exam-
ple, you could use a string buffer:

StringBuffer sb = new StringBuffer();


sb.append(’H’);
sb.append(’a’);
System.out.println(sb);

This works, but it’s ugly. There are ways to avoid the verbosity of this
approach. You can force the + operator to perform string concatenation rather than
addition by ensuring that at least one of its operands is a string. The common
idiom is to begin a sequence of concatenations with the empty string (""), as fol-
lows:

System.out.print("" + ’H’ + ’a’);

This idiom ensures that subexpressions are converted to strings. Although useful it is
a bit ungainly and can lead to some confusion itself.
puzzlers.book Page 27 Thursday, June 9, 2005 10:37 PM

Puzzle 12: ABC 27

Can you guess what the following statement prints? If you aren’t sure, try it:

System.out.println("2 + 2 = " + 2+2);

As of release 5.0, you also have the option of using the printf facility:

System.out.printf("%c%c", ’H’, ’a’);

In summary, use the string concatenation operator with care. The + operator
performs string concatenation if and only if at least one of its operands is of
type String; otherwise, it performs addition. If none of the values to be concate-
nated are strings, you have several choices: prepend the empty string; convert the
first value to a string explicitly, using String.valueOf; use a string buffer; or if
you are using release 5.0, use the printf facility.
This puzzle also contains a lesson for language designers. Operator overload-
ing, even to the limited extent that it is supported in Java, can be confusing. It may
have been a mistake to overload the + operator for string concatenation.

Puzzle 12: ABC


This puzzle asks the musical question, What does this program print?

public class Abc {


public static void main(String[] args) {
String letters = "ABC";
char[] numbers = { ’1’, ’2’, ’3’ };
System.out.println(letters + " easy as " + numbers);
}

ABC
}
puzzlers.book Page 28 Thursday, June 9, 2005 10:37 PM

28 Chapter 3 • Puzzlers with Character

Solution 12: ABC


One would hope that the program prints ABC easy as 123. Unfortunately, it does
not. If you ran it, you found that it prints something like ABC easy as [C@16f0472.
Why is the output so ugly?
Although char is an integral type, many libraries treat it specially, because
char values usually represent characters rather than integers. For example, pass-
ing a char value to println prints a Unicode character rather than its numerical
code. Character arrays get similar special treatment: The char[] overloading of
println prints all of the characters contained in the array, and the char[] over-
loadings of String.valueOf and StringBuffer.append behave analogously.
The string concatenation operator, however, is not defined in terms of these
methods. It is defined to perform string conversion on both of its operands and
then to concatenate the resulting strings. String conversion for object references,
which include arrays, is defined as follows [JLS 15.18.1.1]:

If the reference is null, it is converted to the string "null". Otherwise, the con-
version is performed as if by an invocation of the toString method of the ref-
erenced object with no arguments; but if the result of invoking the toString
method is null, then the string "null" is used instead.

So what is the behavior of invoking toString on a non-null char array?


Arrays inherit the toString method from Object [JLS 10.7], whose specification
says, “Returns a string consisting of the name of the class of which the object is an
instance, the at-sign character ’@’, and the unsigned hexadecimal representation
of the hash code of the object” [Java-API]. The specification for Class.getName
says that the result of invoking this method on the class object for char[] is the
string "[C". Putting it all together gives the ugly string printed by our program.
There are two ways to fix it. You can explicitly convert the array to a string
before invoking string concatenation:

System.out.println(letters + " easy as " +


String.valueOf(numbers));

Alternatively, you can break the System.out.println invocation in two to


make use of the char[] overloading of println:

System.out.print(letters + " easy as ");


System.out.println(numbers);
puzzlers.book Page 29 Thursday, June 9, 2005 10:37 PM

Puzzle 13: Animal Farm 29

Note that these fixes work only if you invoke the correct overloading of the
valueOf or println method. In other words, they depend critically on the com-
pile-time type of the array reference. The following program illustrates this depen-
dency. It looks as though it incorporates the second fix described, but it produces
the same ugly output as the original program because it invokes the Object over-
loading of println instead of the char[] overloading:

// Broken - invokes the wrong overloading of println!


class Abc {
public static void main(String[] args) {
String letters = "ABC";
Object numbers = new char[] { ’1’, ’2’, ’3’ };
System.out.print(letters + " easy as ");
System.out.println(numbers); // Invokes println(Object)
}
}

To summarize, char arrays are not strings. To convert a char array to a


string, invoke String.valueOf(char[]). Some library methods do provide
stringlike support for char arrays, typically having one overloading for Object
and another for char[]; only the latter has the desired behavior.
The lesson for language designers is that the char[] type should probably
have overridden toString to return the characters contained in the array. More
generally, the array types should probably have overridden toString to return a
string representation of the contents of the array.

Puzzle 13: Animal Farm


Readers of George Orwell’s Animal Farm may remember old Major’s pronounce-
ment that “all animals are equal.” The following Java program attempts to test this
pronouncement. What does it print?

public class AnimalFarm {


public static void main(String[] args) {
final String pig = "length: 10";
final String dog = "length: " + pig.length();
System.out.println("Animals are equal: "
+ pig == dog);
}
}
puzzlers.book Page 30 Thursday, June 9, 2005 10:37 PM

30 Chapter 3 • Puzzlers with Character

Solution 13: Animal Farm


A superficial analysis of the program might suggest that it should print
Animals are equal: true. After all, pig and dog are both final String variables
initialized to the character sequence "length: 10". In other words, the strings
referred to by pig and dog are and will forever remain equal to each other. The ==
operator, however, does not test whether two objects are equal; it tests whether
two object references are identical. In other words, it tests whether they refer to
precisely the same object. In this case, they do not.
You may be aware that compile-time constants of type String are interned
[JLS 15.28]. In other words, any two constant expressions of type String that
designate the same character sequence are represented by identical object refer-
ences. If initialized with constant expressions, both pig and dog would indeed
refer to the same object, but dog is not initialized with a constant expression. The
language constrains which operations are permitted to appear in a constant expres-
sion [JLS 16.28], and method invocation is not among them. Therefore the pro-
gram should print Animals are equal: false, right?
Well, no, actually. If you ran the program, you found that it prints false and
nothing else. It doesn’t print Animals are equal: . How could it not print this
string literal, which is right there in black and white? The solution to Puzzle 11
contains a hint: The + operator, whether used for addition or string concatenation,
binds more tightly than the == operator. Therefore, the parameter of the println
method is evaluated like this:

System.out.println(("Animals are equal: " + pig) == dog);

The value of the boolean expression is, of course, false, and that is exactly
what the program prints. There is one surefire way to avoid this sort of difficulty:
When using the string concatenation operator, always parenthesize nontrivial
operands. More generally, when you are not sure whether you need parentheses,
err on the side of caution and include them. If you parenthesize the comparison in
the println statement as follows, it will produce the expected output of
Animals are equal: false:

System.out.println("Animals are equal: " + (pig == dog));

Arguably, the program is still broken. Your code should rarely, if ever,
depend on the interning of string constants. Interning was designed solely to
puzzlers.book Page 31 Thursday, June 9, 2005 10:37 PM

Puzzle 14: Escape Rout 31

reduce the memory footprint of the virtual machine, not as a tool for program-
mers. As this puzzle demonstrates, it isn’t always obvious which expressions will
result in string constants. Worse, if your code depends on interning for its correct
operation, you must carefully keep track of which fields and parameters must be
interned. The compiler can’t check these invariants for you, because interned and
noninterned strings are represented by the same type (String). The bugs that
result from the failure to intern a string are typically quite difficult to detect.
When comparing object references, you should use the equals method in
preference to the == operator unless you need to compare object identity rather
than value. Applying this lesson to our program, here is how the println state-
ment should look. It is clear that the program prints true when it is fixed in this
fashion:

System.out.println("Animals are equal: " + pig.equals(dog));

This puzzle has two lessons for language designers. The natural precedence of
string concatenation might not be the same as that of addition. This implies that it
is problematic to overload the + operator to perform string concatenation, as men-
tioned in Puzzle 11. Also, reference equality is more confusing than value equality
for immutable types, such as String. Perhaps the == operator should perform
value comparisons when applied to immutable reference types. One way to
achieve this would be to make the == operator a shorthand for the equals method,
and to provide a separate method to perform reference identity comparison, akin
to System.identityHashCode.

Puzzle 14: Escape Rout


The following program uses two Unicode escapes, which represent Unicode char-
acters by their hexadecimal numeric codes. What does the program print?

public class EscapeRout {


public static void main(String[] args) {
// \u0022 is the Unicode escape for double quote (")
System.out.println("a\u0022.length() + \u0022b".length());
}
}
puzzlers.book Page 32 Thursday, June 9, 2005 10:37 PM

32 Chapter 3 • Puzzlers with Character

Solution 14: Escape Rout


A naive analysis of the program suggests that it should print 26 because
there are 26 characters between the quotation marks that bound the string
"a\u0022.length() + \u0022b". A deeper analysis suggests that the program
should print 16, as each of the two Unicode escapes requires six characters in the
source file but represents only one character in the string. The string is therefore
ten characters shorter than it appears. Running the program tells a different story.
It prints neither 26 nor 16 but 2.
The key to understanding this puzzle is that Java provides no special treat-
ment for Unicode escapes within string literals. The compiler translates Uni-
code escapes into the characters they represent before it parses the program into
tokens, such as strings literals [JLS 3.2]. Therefore, the first Unicode escape in the
program closes a one-character string literal ("a"), and the second one opens a
one-character string literal ("b"). The program prints the value of the expression
"a".length() + "b".length(), or 2.
If the author of the program had actually wanted this behavior, it would have
been much clearer to say:

System.out.println("a".length() + "b".length());

More likely, the author wanted to put the two double quote characters into the
string literal. You can’t do this with Unicode escapes, but you can do it with
escape sequences [JLS 3.10.6]. The escape sequence representing a double quote
is a backslash followed by a double quote (\"). If the Unicode escapes in the orig-
inal program are replaced with this escape sequence, it will print 16 as expected:

System.out.println("a\".length() + \"b".length());

There are escape sequences for many characters, including the single quote
(\’), linefeed (\n), tab (\t), and backslash (\\). You can use escape sequences in
character literals as well as in string literals. In fact, you can put any ASCII char-
acter into a string literal or a character literal by using a special kind of escape
sequence called an octal escape, but it is preferable to use normal escape
sequences where possible. Both normal escape sequences and octal escapes are far
preferable to Unicode escapes because unlike Unicode escapes, escape sequences
are processed after the program is parsed into tokens.
puzzlers.book Page 33 Thursday, June 9, 2005 10:37 PM

Puzzle 15: Hello Whirled 33

All the programs in this book are written using the ASCII subset of Unicode.
ASCII is the lowest common denominator of character sets. ASCII has only 128
characters, but Unicode has more than 65,000. A Unicode escape can be used to
insert any Unicode character into a program using only ASCII characters. A Uni-
code escape means exactly the same thing as the character that it represents.
Unicode escapes are designed for use when a programmer needs to insert a
character that can’t be represented in the source file’s character set. They are used
primarily to put non-ASCII characters into identifiers, string literals, character lit-
erals, and comments. Occasionally, a Unicode escape adds to the clarity of a pro-
gram by positively identifying one of several similar-looking characters.
In summary, prefer escape sequences to Unicode escapes in string and
character literals. Unicode escapes can be confusing because they are processed
so early in the compilation sequence. Do not use Unicode escapes to represent
ASCII characters. Inside of string and character literals, use escape sequences;
outside of these literals, insert ASCII characters directly into the source file.

Puzzle 15: Hello Whirled


The following program is a minor variation on an old chestnut. What does it print?

/**
* Generated by the IBM IDL-to-Java compiler, version 1.0
* from F:\TestRoot\apps\a1\units\include\PolicyHome.idl
* Wednesday, June 17, 1998 6:44:40 o’clock AM GMT+00:00
*/
public class Test {
public static void main(String[] args) {
System.out.print("Hell");
System.out.println("o world");
}
}
puzzlers.book Page 34 Thursday, June 9, 2005 10:37 PM

34 Chapter 3 • Puzzlers with Character

Solution 15: Hello Whirled


This puzzle looks fairly straightforward. The program contains two statements.
The first prints Hell and the second prints o world on the same line, effectively
concatenating the two strings. Therefore, you might expect the program to print
Hello world. You would be sadly mistaken. In fact, it doesn’t compile.
The problem is in the third line of the comment, which contains the characters
\units. These characters begin with a backslash (\) followed by the letter u,
which denotes the start of a Unicode escape. Unfortunately, these characters are
not followed by four hexadecimal digits, so the Unicode escape is ill-formed, and
the compiler is required to reject the program. Unicode escapes must be well
formed, even if they appear in comments.
It is legal to place a well-formed Unicode escape in a comment, but there is
rarely a reason to do so. Programmers sometimes use Unicode escapes in Javadoc
comments to generate special characters in the documentation:

// Questionable use of Unicode escape in Javadoc comment

/**
* This method calls itself recursively, causing a
* <tt>StackOverflowError</tt> to be thrown.
* The algorithm is due to Peter von der Ah\u00E9.
*/

This technique represents an unnecessary use of Unicode escapes. Use HTML


entity escapes instead of Unicode escapes in Javadoc comments:

/**
* This method calls itself recursively, causing a
* <tt>StackOverflowError</tt> to be thrown.
* The algorithm is due to Peter von der Ah&eacute;.
*/

Either of the preceding comments should cause the name to appear in the docu-
mentation as “Peter von der Ahé,” but the latter comment is also understandable in
the source file.
In case you were wondering, the comment in this puzzle was derived from an
actual bug report. The program was machine generated, which made it difficult to
track the problem down to its source, an IDL-to-Java compiler. To avoid placing
other programmers in this position, tools must not put Windows filenames into
puzzlers.book Page 35 Thursday, June 9, 2005 10:37 PM

Puzzle 16: Line Printer 35

comments in generated Java source files without first processing them to elimi-
nate backslashes.
In summary, ensure that the characters \u do not occur outside the context of a
valid Unicode escape, even in comments. Be particularly wary of this problem in
machine-generated code.

Puzzle 16: Line Printer


The line separator is the name given to the character or characters used to separate
lines of text, and varies from platform to platform. On Windows, it is the CR char-
acter (carriage return) followed by the LF character (linefeed). On UNIX, it is the
LF character alone, often referred to as the newline character. The following pro-
gram passes this character to println. What does it print? Is its behavior platform
dependent?

public class LinePrinter {


public static void main(String[] args) {
// Note: \u000A is Unicode representation of linefeed (LF)
char c = 0x000A;
System.out.println(c);
}
}
puzzlers.book Page 36 Thursday, June 9, 2005 10:37 PM

36 Chapter 3 • Puzzlers with Character

Solution 16: Line Printer


The behavior of this program is platform independent: It won’t compile on any
platform. If you tried to compile it, you got an error message that looks something
like this:

LinePrinter.java:3: ’;’ expected


// Note: \u000A is Unicode representation of linefeed (LF)
^
1 error

If you are like most people, this message did not help to clarify matters.
The key to this puzzle is the comment on the third line of the program. Like the
best of comments, this one is true. Unfortunately, this one is a bit too true. The com-
piler not only translates Unicode escapes into the characters they represent before
it parses a program into tokens (Puzzle 14), but it does so before discarding com-
ments and white space [JLS 3.2].
This program contains a single Unicode escape (\u000A), located in its sole
comment. As the comment tells you, this escape represents the linefeed character,
and the compiler duly translates it before discarding the comment. Unfortunately,
this linefeed character is the first line terminator after the two slash characters that
begin the comment (//) and so terminates the comment [JLS 3.4]. The words fol-
lowing the escape (is Unicode representation of linefeed (LF)) are therefore
not part of the comment; nor are they syntactically valid.
To make this more concrete, here is what the program looks like after the Uni-
code escape has been translated into the character it represents:

public class LinePrinter {


public static void main(String[] args) {
// Note:
is Unicode representation of linefeed (LF)
char c = 0x000A;
System.out.println(c);
}
}
puzzlers.book Page 37 Thursday, June 9, 2005 10:37 PM

Puzzle 17: Huh? 37

The easiest way to fix the program is to remove the Unicode escape from the
comment, but a better way is to initialize c with an escape sequence instead of a
hex integer literal, obviating the need for the comment:

public class LinePrinter {


public static void main(String[] args) {
char c = ’\n’;
System.out.println(c);
}
}

Once this has been done, the program will compile and run, but it’s still a
questionable program. It is platform dependent for exactly the reason suggested in
the puzzle. On certain platforms, such as UNIX, it will print two complete line
separators; on others, such as Windows, it won’t. Although the output may look
the same to the naked eye, it could easily cause problems if it were saved in a file
or piped to another program for subsequent processing.
If you want to print two blank lines, you should invoke println twice. As of
release 5.0, you can use printf instead of println, with the format string
"%n%n". Each occurrence of the characters %n will cause printf to print the
appropriate platform-specific line separator.
Hopefully, the last three puzzles have convinced you that Unicode escapes can
be thoroughly confusing. The lesson is simple: Avoid Unicode escapes except
where they are truly necessary. They are rarely necessary.

Puzzle 17: Huh?


Is this a legal Java program? If so, what does it print?

\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020\u0020
\u0063\u006c\u0061\u0073\u0073\u0020\u0055\u0067\u006c\u0079
\u007b\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020
\u0020\u0020\u0020\u0020\u0073\u0074\u0061\u0074\u0069\u0063
\u0076\u006f\u0069\u0064\u0020\u006d\u0061\u0069\u006e\u0028
\u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u0020\u0020
\u0020\u0020\u0020\u0020\u0061\u0072\u0067\u0073\u0029\u007b
\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074
\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0020
\u0022\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u0022\u002b
\u0022\u006f\u0072\u006c\u0064\u0022\u0029\u003b\u007d\u007d
puzzlers.book Page 38 Thursday, June 9, 2005 10:37 PM

38 Chapter 3 • Puzzlers with Character

Solution 17: Huh?


Of course it’s a legal Java program! Isn’t it obvious? It prints Hello world. Well,
maybe it isn’t so obvious. In fact, the program is totally incomprehensible. Each
time you use a Unicode escape unnecessarily, you make your program a bit less
comprehensible, and this program takes the concept to its logical extreme. In case
you are curious, here is what the program looks like after the Unicode escapes are
translated to the characters they represent:

public
class Ugly
{public
static
void main(
String[]
args){
System.out
.println(
"Hello w"+
"orld");}}

Here is how it looks after cleaning up the formatting:

public class Ugly {


public static void main(String[] args) {
System.out.println("Hello w" + "orld");
}
}

The lesson of this puzzle is: Just because you can doesn’t mean you should.
Alternatively, If it hurts when you do it, don’t do it! More seriously, this puzzle
serves to reinforce the lessons of the previous three: Unicode escapes are essen-
tial when you need to insert characters that can’t be represented in any other
way into your program. Avoid them in all other cases. Unicode escapes reduce
program clarity and increase the potential for bugs.
For language designers, perhaps it should be illegal to use Unicode escapes to
represent ASCII characters. This would make the programs in Puzzles 14, 15, and
17 (this puzzle) invalid, eliminating a great deal of confusion. This restriction
would cause no great hardship to programmers.
character.fm Page 39 Thursday, April 20, 2006 10:17 PM

Puzzle 18: String Cheese 39

Puzzle 18: String Cheese


This program creates a string from a sequence of bytes, then iterates over the char-
acters in the string and prints them as numbers. Describe the sequence of numbers
that the program prints:

public class StringCheese {


public static void main(String[] args) {
byte[] bytes = new byte[256];
for(int i = 0; i < 256; i++)
bytes[i] = (byte)i;
String str = new String(bytes);
for(int i = 0, n = str.length(); i < n; i++)
System.out.print((int)str.charAt(i) + " ");
}
}
puzzlers.book Page 40 Thursday, June 9, 2005 10:37 PM

40 Chapter 3 • Puzzlers with Character

Solution 18: String Cheese


First, the byte array is initialized with every possible byte value from 0 to 255.
Then these byte values are translated into char values by the String constructor.
Finally, the char values are cast to int values and printed. The printed values are
guaranteed to be nonnegative, because char values are unsigned, so you might
expect the program to print the integers from 0 to 255 in order.
If you ran the program, maybe you saw this sequence. Then again, maybe you
didn’t. We ran it on four machines and saw four different sequences, including the
one described previously. This program isn’t even guaranteed to terminate nor-
mally, much less to print any particular sequence. Its behavior is completely
unspecified.
The culprit here is the String(byte[]) constructor. Its specification says:
“Constructs a new String by decoding the specified byte array using the plat-
form’s default charset. The length of the new String is a function of the charset,
and hence may not be equal to the length of the byte array. The behavior of this
constructor when the given bytes are not valid in the default charset is unspeci-
fied” [Java-API].
What exactly is a charset? Technically, it is “the combination of a coded char-
acter set and a character-encoding scheme” [Java-API]. In other words, a charset
is a bunch of characters, the numerical codes that represent them, and a way to
translate back and forth between a sequence of character codes and a sequence of
bytes. The translation scheme differs greatly among charsets. Some have a one-to-
one mapping between characters and bytes; most do not. The only default charset
that will make the program print the integers from 0 to 255 in order is ISO-8859-1,
more commonly known as Latin-1 [ISO-8859-1].
A J2SE Runtime Environment’s default charset depends on the underlying
operating system and locale. If you want to know your JRE’s default charset and
you are using release 5.0 or a later release, you can find out by invoking
java.nio.charset.Charset.defaultCharset(). If you are using an earlier
release, you can find out by reading the system property "file.encoding".
Luckily, you are not forced to put up with the vagaries of default charsets.
When translating between char sequences and byte sequences, you can and
usually should specify a charset explicitly. A String constructor that takes a
charset name in addition to a byte array is provided for this purpose. If you
replace the String constructor invocation in the original program with the one
puzzlers.book Page 41 Thursday, June 9, 2005 10:37 PM

Puzzle 19: Classy Fire 41

that follows, the program is guaranteed to print the integers from 0 to 255 in order,
regardless of the default charset:

String str = new String(bytes, "ISO-8859-1");

This constructor is declared to throw UnsupportedEncodingException, so


you must catch it or, preferably, declare the main method to throw it, or the pro-
gram won’t compile. The program won’t actually throw the exception, though.
The specification for Charset mandates that every implementation of the Java
platform support certain charsets, and ISO-8859-1 is among them.
The lesson of this puzzle is that every time you translate a byte sequence to
a String, you are using a charset, whether you specify it explicitly or not. If
you want your program to behave predictably, specify a charset each time you use
one. For API designers, perhaps it was not such a good idea to provide a
String(byte[]) constructor that depends on the default charset.

Puzzle 19: Classy Fire


The following program uses a method to classify characters. What does the pro-
gram print? In case you are not familiar with the String.indexOf(char) method,
it returns the index of the first occurrence of the specified character in the string,
or −1 if the string doesn’t contain the character:

public class Classifier {


public static void main(String[] args) {
System.out.println(
classify(’n’) + classify(’+’) + classify(’2’));
}
static String classify(char ch) {
if ("0123456789".indexOf(ch) >= 0)
return "NUMERAL ";
if ("abcdefghijklmnopqrstuvwxyz".indexOf(ch) >= 0)
return "LETTER ";
/* (Operators not supported yet)
if ("+-*/&|!=".indexOf(ch) >= 0)
return "OPERATOR ";
*/
return "UNKNOWN ";
}
}
puzzlers.book Page 42 Thursday, June 9, 2005 10:37 PM

42 Chapter 3 • Puzzlers with Character

Solution 19: Classy Fire


If you guessed that this program prints LETTER UNKNOWN NUMBER, you fell for the
trap. The program doesn’t even compile. Let’s take another look at the relevant
section, this time highlighting the block comment in boldface:

if ("abcdefghijklmnopqrstuvwxyz".indexOf(ch) >= 0)
return "LETTER ";
/* (Operators not supported yet)
if ("+-*/&|!=".indexOf(ch) >= 0)
return "OPERATOR ";
*/
return "UNKNOWN ";
}
}

As you can see, the comment ends inside the string, which quite naturally
contains the characters */. The resulting program is syntactically invalid. Our
attempt to comment out a section of the program failed because string literals are
not treated specially within comments.
More generally, the text inside of comments is not treated specially in any way
[JLS 3.7]. Therefore, block comments do not nest. Consider the following code
snippet:

/* Add the numbers from 1 to n */


int sum = 0;
for (int i = 1; i <= n; i++)
sum += i;

Now suppose that we try to comment out the snippet with a block comment.
Again, we highlight the entire comment in boldface:

/*
/* Add the numbers from to 1 to n */
int sum = 0;
for (int i = 1; i <= n; i++)
sum += i;
*/

As you can see, we failed to comment out the original snippet. On the bright
side, the resulting code contains a syntax error, so the compiler will tell us that we
have a problem.
puzzlers.book Page 43 Thursday, June 9, 2005 10:37 PM

Puzzle 20: What’s My Class? 43

You may occasionally see a section of code that is disabled with an if state-
ment whose boolean expression is the constant false:

// Code commented out with an if statement - doesn’t always work!


if (false) {
/* Add the numbers from 1 to n */
int sum = 0;
for (int i = 1; i <= n; i++)
sum += i;
}

The language specification recommends this as a technique for conditional compi-


lation [JLS 14.21], but it is not well suited to commenting out code. It can’t be
used unless the code to be disabled is a sequence of valid statements.
The best way to comment out a section of code is to use a sequence of sin-
gle-line comments. Most IDEs automate this process:

// Code commented out with a sequence of single-line comments


// /* Add the numbers from 1 to n */
// int sum = 0;
// for (int i = 1; i <= n; i++)
// sum += i;

In summary, a block comment does not reliably comment out a section of


code. Use a sequence of single-line comments instead. For language designers,
note that nestable block comments are not a good idea. They force the compiler to
parse the text inside block comments, which causes more problems than it solves.

Puzzle 20: What’s My Class?


This program was designed to print the name of its class file. In case you aren’t
familiar with class literals, Me.class.getName() returns the fully qualified name
of the class Me, or "com.javapuzzlers.Me". What does the program print?

package com.javapuzzlers;
public class Me {
public static void main(String[] args) {
System.out.println(
Me.class.getName().replaceAll(".", "/") + ".class");
}
}
puzzlers.book Page 44 Thursday, June 9, 2005 10:37 PM

44 Chapter 3 • Puzzlers with Character

Solution 20: What’s My Class?


The program appears to obtain its class name ("com.javapuzzlers.Me"), replace
all occurrences of the string "." with "/", and append the string ".class". You
might think that the program would print com/javapuzzlers/Me.class, which is
the class file from which it was loaded. If you ran the program, you found that it
actually prints ///////////////////.class. What’s going on here? Are we a
victim of the slasher?
The problem is that String.replaceAll takes a regular expression as its
first parameter, not a literal sequence of characters. (Regular expressions were
added to the Java platform in release 1.4.) The regular expression "." matches any
single character, and so every character of the class name is replaced by a slash,
producing the output we saw.
To match only the period character, the period in the regular expression must
be escaped by preceding it with a backslash (\). Because the backslash character
has special meaning in a string literal—it begins an escape sequence—the back-
slash itself must be escaped with a second backslash. This produces an escape
sequence that generates a backslash in the string literal. Putting it all together, the
following program prints com/javapuzzlers/Me.class as expected:

package com.javapuzzlers;

public class Me {
public static void main(String[] args) {
System.out.println(
Me.class.getName().replaceAll("\\.", "/") + ".class");
}
}

To solve this kind of problem, release 5.0 provides the new static method
java.util.regex.Pattern.quote. It takes a string as a parameter and adds any
necessary escapes, returning a regular expression string that matches the input
puzzlers.book Page 45 Thursday, June 9, 2005 10:37 PM

Puzzle 21: What’s My Class, Take 2 45

string exactly. Here is how the program looks when modified to make use of this
method:

package com.javapuzzlers;
import java.util.regex.Pattern;

public class Me {
public static void main(String[] args) {
System.out.println(Me.class.getName().
replaceAll(Pattern.quote("."), "/") + ".class");
}
}

Another problem with this program is that the correct behavior is platform
dependent. Not all file systems use the slash character to separate hierarchical file-
name components. To get a valid filename for the platform on which you are run-
ning, you should use the correct platform-dependent separator character in place
of the slash. That is exactly what the next puzzle does.

Puzzle 21: What’s My Class, Take 2


This program does exactly what the one in the previous puzzle did, but doesn’t
assume that the slash character is used to separate filename components. Instead,
the program uses java.io.File.separator, which is a public String field spec-
ified to contain the platform-specific filename separator. Does the program print
the correct platform-specific name of the class file from which it was loaded?

package com.javapuzzlers;
import java.io.File;

public class MeToo {


public static void main(String[] args) {
System.out.println(MeToo.class.getName().
replaceAll("\\.", File.separator) + ".class");
}
}
puzzlers.book Page 46 Thursday, June 9, 2005 10:37 PM

46 Chapter 3 • Puzzlers with Character

Solution 21: What’s My Class, Take 2


The program displays one of two behaviors depending on the underlying platform.
If the file separator is a slash, as it is on UNIX, the program prints com/
javapuzzlers/MeToo.class, which is correct. If, however, the file separator is a
backslash, as it is on Windows, the program prints something like this:

Exception in thread "main"


StringIndexOutOfBoundsException: String index out of range: 1
at java.lang.String.charAt(String.java:558)
at java.util.regex.Matcher.appendReplacement(Matcher.java:696)
at java.util.regex.Matcher.replaceAll(Matcher.java:806)
at java.lang.String.replaceAll(String.java:2000)
at com.javapuzzlers.MeToo.main(MeToo.java:6)

Although this behavior is platform dependent, it isn’t exactly what we were


looking for. What went wrong on Windows? It turns out that the second parameter
of String.replaceAll is a not an ordinary string but a replacement string, as
defined in the java.util.regex specification [Java-API]. A backslash appearing
in a replacement string escapes the following character, causing it to be treated lit-
erally. When you run the program on Windows, the replacement string is a lone
backslash character, which is invalid. Admittedly, the exception could be a little
more informative.
So how do you solve this problem? Release 5.0 provides not one but two new
methods that solve it. One is java.util.regex.Matcher.quoteReplacement,
which translates a string into the corresponding replacement string. Here is how to
fix the program by using this method:

System.out.println(MeToo.class.getName().replaceAll(
"\\.", Matcher.quoteReplacement(File.separator))
+ ".class");

The second method introduced in release 5.0 provides an even better solution.
This method, String.replace(CharSequence, CharSequence), does the same
thing as String.replaceAll, but treats both the pattern and the replacement as
literal strings. Here is how to fix the program by using this method:

System.out.println(MeToo.class.getName().
replace(".", File.separator) + ".class");
puzzlers.book Page 47 Thursday, June 9, 2005 10:37 PM

Puzzle 22: Dupe of URL 47

But what if you are using an earlier Java release? Unfortunately, there is no
easy way to generate the replacement string. It is easier to dispense with regular
expressions entirely and to use String.replace(char, char):

System.out.println(MeToo.class.getName().
replace(’.’, File.separatorChar) + ".class");

The main lesson of this puzzle and the previous one is: Be careful when
using unfamiliar library methods. When in doubt, consult the Javadoc. Also,
regular expressions are tricky: Problems tend to show up at run time rather than
compile time.
For API designers, it is important to use a method-naming scheme that distin-
guishes methods whose behavior differs in significant ways. Java’s String class is
not perfect in this regard. For many programmers, it is not easy to remember
which string-replacement methods use literal strings and which ones use regular
expressions or replacement strings.

Puzzle 22: Dupe of URL


This puzzle takes advantage of a little-known feature of the Java programming
language. What does this program do?

public class BrowserTest {


public static void main(String[] args) {
System.out.print("iexplore:");
http://www.google.com;
System.out.println(":maximize");
}
}
puzzlers.book Page 48 Thursday, June 9, 2005 10:37 PM

48 Chapter 3 • Puzzlers with Character

Solution 22: Dupe of URL


This is a bit of a trick question. The program doesn’t do anything special. It sim-
ply prints iexplore::maximize. The URL that appears in the middle of the pro-
gram is a statement label [JLS 14.7] followed by an end-of-line comment
[JLS 3.7]. Labels are rarely needed in Java, which thankfully lacks a goto state-
ment. The “little-known feature of the Java programming language” to which the
puzzle refers is that you are allowed to put a label on any statement. This program
labels an expression statement, which is legal but useless.
For what it’s worth, this would be a more reasonable way to format the pro-
gram, assuming that you really want to include the label:

public class BrowserTest {


public static void main(String[] args) {
System.out.print("iexplore:");

http: // www.google.com;
System.out.println(":maximize");
}
}

That said, there is no earthly reason to include the label or the comment, which
has nothing to do with the program.
The lesson of this puzzle is that misleading comments and extraneous code
cause confusion. Write comments carefully and keep them up to date. Excise
dead code. Also, if something seems too strange to be true, it’s probably false.
puzzlers.book Page 49 Thursday, June 9, 2005 10:37 PM

Puzzle 23: No Pain, No Gain 49

Puzzle 23: No Pain, No Gain


This program prints a word, using a random number generator to select the first
character. Describe the behavior of the program:

import java.util.Random;

public class Rhymes {


private static Random rnd = new Random();

public static void main(String[] args) {


StringBuffer word = null;
switch(rnd.nextInt(2)) {
case 1: word = new StringBuffer(’P’);
case 2: word = new StringBuffer(’G’);
default: word = new StringBuffer(’M’);
}
word.append(’a’);
word.append(’i’);
word.append(’n’);
System.out.println(word);
}
}
puzzlers.book Page 50 Thursday, June 9, 2005 10:37 PM

50 Chapter 3 • Puzzlers with Character

Solution 23: No Pain, No Gain


At first glance, this program might appear to print out the words Pain, Gain, and
Main with equal likelihood, varying from run to run. It appears to choose the first
letter of the word, depending on the value chosen by the random number genera-
tor: M for 0, P for 1, and G for 2. The puzzle’s title might have provided you with a
clue that it doesn’t actually print Pain or Gain. Perhaps more surprisingly, it
doesn’t print Main either, and its behavior doesn’t vary from run to run. It always
prints ain.
Three bugs conspire to cause this behavior. Did you spot them all? The first
bug is that the random number is chosen so the switch statement can reach only
two of its three cases. The specification for Random.nextInt(int) says: “Returns
a pseudorandom, uniformly distributed int value between 0 (inclusive) and the
specified value (exclusive)” [Java-API]. This means that the only possible values
of the expression rnd.nextInt(2) are 0 and 1. The switch statement will never
branch to case 2, which suggests that the program will never print Gain. The
parameter to nextInt should have been 3 rather than 2.
This is a fairly common source of problems, known as a fencepost error. The
name comes from the common but incorrect answer of 10 to the question, If you
build a fence 100 feet long with posts 10 feet apart, how many posts do you need?
Both 11 and 9 are correct answers, depending on whether there are posts at the
ends of the fence, but 10 is wrong. Watch out for fencepost errors. Whenever
you are working with lengths, ranges, or moduli, be careful to determine which
endpoints should be included, and make sure that your code behaves accordingly.
The second bug is that there are no break statements between the cases.
Whatever the value of the switch expression, the program will execute that case
and all subsequent cases [JLS 14.11]. Each case assigns a value to the variable
word, and the last assignment wins. The last assignment will always be the one in
the final case (default), which is new StringBuffer(’M’). This suggests that the
program will never print Pain or Gain but always Main.
The absence of break statements in switch cases is a common error that tools
can help you catch. As of release 5.0, javac provides the -Xlint:fallthrough
flag to generate warnings when you forget a break between one case and the next.
Don’t fall through from one nonempty case to another. It’s bad style because
it’s unusual and therefore confusing to the reader. Nine times out of ten, it indi-
cates an error. If Java had not been modeled after C, its switch statement would
puzzlers.book Page 51 Thursday, June 9, 2005 10:37 PM

Puzzle 23: No Pain, No Gain 51

probably not require breaks. The lesson for language designers is to consider pro-
viding a structured switch statement.
The last and most subtle bug is that the expression new StringBuffer(’M’)
probably does not do what you think it does. You may not be familiar with the
StringBuffer(char) constructor, and with good reason: It does not exist. There
is a parameterless constructor, one that takes a String indicating the initial con-
tents of the string buffer and one that takes an int indicating its initial capacity. In
this case, the compiler selects the int constructor, applying a widening primitive
conversion to convert the char value ’M’ into the int value 77 [JLS 5.1.2]. In
other words, new StringBuffer(’M’) returns an empty string buffer with an ini-
tial capacity of 77. The remainder of the program appends the characters a, i, and
n to the empty string buffer and prints out its contents, which are always ain.
To avoid this kind of problem, use familiar idioms and APIs whenever pos-
sible. If you must use unfamiliar APIs, read the documentation carefully. In
this case, the program should have used the common StringBuffer constructor
that takes a String.
This corrected version of the program fixes all three bugs, printing Pain,
Gain, and Main with equal likelihood:

import java.util.Random;

public class Rhymes {


private static Random rnd = new Random();

public static void main(String[] args) {


StringBuffer word = null;
switch(rnd.nextInt(3)) {
case 1:
word = new StringBuffer("P");
break;
case 2:
word = new StringBuffer("G");
break;
default:
word = new StringBuffer("M");
break;
}
word.append(’a’);
word.append(’i’);
word.append(’n’);
System.out.println(word);
}
}
puzzlers.book Page 52 Thursday, June 9, 2005 10:37 PM

52 Chapter 3 • Puzzlers with Character

Although this program fixes the bugs, it is overly verbose. Here is a more elegant
version:

import java.util.Random;

public class Rhymes {


private static Random rnd = new Random();
public static void main(String args[]) {
System.out.println("PGM".charAt(rnd.nextInt(3)) + "ain");
}
}

Better still is the following version. Although slightly longer, it is more gen-
eral. It does not depend on the fact that the possible outputs differ only in their
first characters:

import java.util.Random;

public class Rhymes {


public static void main(String args[]) {
String a[] = {"Main", "Pain", "Gain"};
System.out.println(randomElement(a));
}

private static Random rnd = new Random();


private static String randomElement(String[] a) {
return a[rnd.nextInt(a.length)];
}
}

To summarize: First, be careful of fencepost errors. Second, remember to put


a break after each case in switch statements. Third, use common idioms and
APIs, and consult the documentation when you stray from the well-worn path.
Fourth, a char is not a String but is more like an int. Finally, watch out for
sneaky puzzlers.
Google
Bookmarks Delicious Digg Facebook StumbleUpon Reddit Twitter

Java_Rock_Star_CH_Openers.indd 3 6/18/09 11:52:02 AM


Jim Clarke
Jim Connors
Eric Bruno


JavaFX

Build Rich Applications that Run on the Web, Desktops, Mobile Devices...
Anywhere!
AVAILABLE
• BOOK: 9780137012879
Using JavaFX, developers and graphic designers can work together to build robust,
• SAFARI ONLINE
immersive applications and deploy them anywhere: on the Web, on the desktop, and on
millions of Java-enabled mobile devices. Now, three of Sun’s leading JavaFX innovators • EBOOK: 0137013523
present the definitive, easy-to-use introduction to this breakthrough platform. • KINDLE: 013701354X

JavaFX™ brings together all the knowledge, techniques, and reusable code you need to
quickly deliver production-quality solutions. Writing for both developers and designers,
About the Authors
the authors explain how JavaFX simplifies and improves the Rich Internet Application Jim Clarke, principal technolo-
development process, and they show how to make the most of its ready-built components gist with Sun Microsystems, has
and frameworks. spent twelve years developing with
the Java platform. He has worked
The first book to cover the new JavaFX 1.1 release, JavaFX™ covers everything from with JavaFX for more than two
data integration to multimedia, special effects to REST. Drawing on their unsurpassed
years and served on the JavaFX
experience, the authors present a full chapter of design patterns and a complete case study
compiler team.
application. This book’s wide-ranging content includes:
Jim Connors, a long-time
• Building and running JavaFX programs
• Understanding the role of graphics designers in creating JavaFX Graphical Assets member of Sun’s system engineer-
• Writing fast, efficient JavaFX Script programs ing community, has spent a de-
• Using data binding to simplify Model-View-Controller application design cade helping customers leverage
• Creating rich user experiences with JavaFX visual components Java technologies ranging from
• Bringing user interfaces to life with lighting, reflection, and other special effects Java Card and Java ME to Java EE
• Adding motion with the JavaFX animation framework and JavaFX.
• Incorporating pictures, sound, and videos in your applications
• Creating RESTful applications with JSON and XML Eric Bruno, systems engineer
• Writing JavaFX applications that make the most of the underlying Java platform at Sun, is author of Java
Messaging (Charles River
Media, 2005) and Real-Time
Java™ Programming (Prentice
Hall, 2009) and is currently
contributing editor and blogger
for Dr. Dobb’s Journal.

informit.com/aw

Java_Rock_Star_CH_Openers.indd 4 6/18/09 11:52:04 AM


Clarke.book Page 33 Wednesday, May 6, 2009 10:00 AM

3
JavaFX Primer
“I’m still at the beginning of my career. It’s all a little new,
and I’m still learning as I go.”
—Orlando Bloom

JavaFX Script Basics


JavaFX is partially a declarative language. Using a declarative language, a devel-
oper describes what needs to be done, then lets the system get it done. Olof Torg-
ersson, Program Director for the Chalmers University of Technology Master’s
program in Interaction Design and Associate Professor at Göteborg University,
has been researching declarative programming for over 10 years. From his anal-
ysis of declarative programming approaches, we find this definition:
“From a programmer’s point of view, the basic property is that program-
ming is lifted to a higher level of abstraction. At this higher level of
abstraction the programmer can concentrate on stating what is to be
computed, not necessarily how it is to be computed”1
JavaFX Script blends declarative programming concepts with object orientation.
This provides a highly productive, yet flexible and robust, foundation for appli-
cations. However, with this flexibility comes responsibility from the developer.
JavaFX Script is a forgiving language and being declarative, it assumes inherent
rules that may obscure a programming fault. The most obvious of these is that
null objects are handled by the runtime engine and seldom cause a Java Null
Pointer exception. As a result, the program will continue when a null is encountered

1. Torgersson, Olof. “A Note on Declarative Programming Paradigms and the Future of Defini-
tional Programming,” Chalmers University of Technology and Göteborg University, Göteborg,
Sweden. http://www.cs.chalmers.se/~oloft/Papers/wm96/wm96.html.

33
Clarke.book Page 34 Wednesday, May 6, 2009 10:00 AM

34 CHAPTER 3 JAVAFX PRIMER

within an expression, and will produce a valid result. However, the result may
not have been what you expected. Therefore, the developer needs to be extra vig-
ilant when writing code and more thorough when testing it. At first, this may
seem alarming; however, this is offset by the ease of use and greater productivity
of JavaFX and by the fact that JavaFX tries to mitigate the user from experienc-
ing a crash.
One of the benefits of JavaFX being a declarative language is that much of the
“plumbing” to make objects interact is already provided within the language.
This allows the developer to be able to concentrate more on what needs to display,
and less on how to do it. The next sections provide an overview of the JavaFX
Script language including syntax, operators, and other features.

JavaFX Script Language


As we already mentioned, JavaFX Script is a declarative scripting language with
object-oriented support. If you are already acquainted with other languages such
as Java, JavaScript, Groovy, Adobe ActionScript, or JRuby, JavaFX Script will
look familiar, but there are significant differences. While supporting traditional
pure scripting, it also supports the encapsulation and reuse capabilities afforded
by object orientation. This allows the developer to use JavaFX to produce and
maintain small- to large-scale applications. Another key feature is that JavaFX
Script seamlessly integrates with Java.
Conceptually, JavaFX Script is broken down into two main levels, script and
class. At the script level, variables and functions may be defined. These may be
shared with other classes defined within the script, or if they have wider access
rights, they may be shared with other scripts and classes. In addition, expressions
called loose expressions may be created. These are all expressions declared out-
side of a class definition. When the script is evaluated, all loose expressions are
evaluated.
A very simple script to display Hello World to the console is

println("Hello World");

Another example, showing how to do a factorial of 3, is shown in Listing 3.1.

Listing 3.1 Factorial of 3


def START = 3;
var result = START;
Clarke.book Page 35 Wednesday, May 6, 2009 10:00 AM

JAVAFX SCRIPT LANGUAGE 35

var a = result - 1;
while(a > 0) {
result *= a;
a--;
}
println("result = {result}");

Developer Note: If your script has exported members—that is, any external
accessible members such as public, protected, and package, functions or vari-
ables—then all loose expressions must be contained in a run function. For exam-
ple, if we change the result variable in the previous example to add public
visibility, we need to create the run function.

public var result:Number;

function run(args : String[]) : java.lang.Object {

var num = if(sizeof args > 0) {


java.lang.Integer.valueOf(args[0]);
} else {
10;
};

result = num;
var a = result - 1;
while(a > 0) {
result *= a;
a--;
}
println("{num}! = {result}");
}

The run method contains an optional String[] parameter, which is a sequence of


the command-line arguments passed to the script when it runs.
If you do not have exported members, you can still include a run method. How-
ever, the run method, itself, is considered exported, even if you do not include an
access modifier with it. So, once you add a run method, all loose exported expres-
sions must now be contained within it.

Apart from the script level, a class defines instance variables and functions and
must first be instantiated into an object before being used. Class functions or
variables may access script level functions or variables within the same script
file, or from other script files if the appropriate access rights are assigned. On the
other hand, script level functions can only access class variables and functions if
the class is created into an object and then only if the class provides the appropri-
ate access rights. Access rights are defined in more detail later in this chapter.
Clarke.book Page 36 Wednesday, May 6, 2009 10:00 AM

36 CHAPTER 3 JAVAFX PRIMER

Class Declaration
To declare a class in JavaFX, use the class keyword.

public class Title {


}

Developer Note: By convention, the first letter of class names is capitalized.

The public keyword is called an access modifier and means that this class can
be used by any other class or script, even if that class is declared in another script
file. If the class does not have a modifier, it is only accessible within the script
file where it is declared. For example, the class Point in Listing 3.2 does not
have a visibility modifier, so it is only has script visibility and can only be used
within the ArtWork script.

Listing 3.2 Artwork.fx

class Point {// private class only


//visible to the ArtWork class
var x:Number;
var y:Number;
}

public class ArtWork {


var location: Point;
}

Developer Note: For each JavaFX script file, there is a class generated using
that script filename, even if one is not explicitly defined. For example, in the previ-
ous example for ArtWork.fx, there is a class ArtWork. This is true even if we had
not included the public class ArtWork declaration.
Also, all other classes defined within the script file have their name prepended with
the script file’s name. For example, in the previous example, class Point is fully quali-
fied as ArtWork.Point. Of course, if ArtWork belongs to a package, the package name
would also be used to qualify the name. For example, com.acme.ArtWork.Point.

To extend a class, use the extends keyword followed by the more generalized
class name. JavaFX classes can extend at most one Java or JavaFX class. If you
extend a Java class, that class must have a default (no-args) constructor.
Clarke.book Page 37 Wednesday, May 6, 2009 10:00 AM

CLASS DECLARATION 37

public class Porsche911 extends Porsche {


}

JavaFX may extend multiple JavaFX mixin classes or Java interfaces. Mixin
classes are discussed in the next section.
An application may contain many classes, so it is helpful to organize them in a
coherent way called packages. To declare that your class or script should belong
to a package, include a package declaration at the beginning of the script file.
The following example means that the Title class belongs to the
com.mycompany.components package. The full name of the Title class is now
com.mycompany.components.Title. Whenever the Title class is referenced, it
must be resolved to this full name.

package com.mycompany.components;
public class Title {
}

To make this resolution easier, you can include an import statement at the top of
your source file. For example:

import com.mycompany.components.Title;

var productTitle = Title{};

Now, wherever Title is referenced within that script file, it will resolve to
com.mycompany.components.Title. You can also use a wildcard import declaration:

import com.mycompany.components.*;

With the wildcard form of import, whenever you refer to any class in the
com.mycompany.components package, it will resolve to its full name. The fol-
lowing code example shows how the class names are resolved, showing the fully
qualified class name in comments.

package com.mycompany.myapplication;
import com.mycompany.components.Title;

// com.mycompany.myapplication.MyClass
public class MyClass {
// com.mycompany.components.Title
public var title: Title;
}

A class can have package visibility by using the package keyword instead of public.
This means the class can only be accessed from classes within the same package.
Clarke.book Page 38 Wednesday, May 6, 2009 10:00 AM

38 CHAPTER 3 JAVAFX PRIMER

package class MyPackageClass {


}

A class may also be declared abstract, meaning that this class cannot be instan-
tiated directly, but can only be instantiated using one of its subclasses. Abstract
classes are not intended to stand on their own, but encapsulate a portion of
shared state and functions that several classes may use. Only a subclass of an
abstract class can be instantiated, and typically the subclass has to fill in those
unique states or behavior not addressed in the abstract class.

public abstract class MyAbstractClass {


}

If a class declares an abstract function, it must be declared abstract.

public abstract class AnotherAbstractClass {


public abstract function
setXY(x:Number, y:Number) : Void;
}

Mixin Classes
JavaFX supports a form of inheritance called mixin inheritance. To support this,
JavaFX includes a special type of class called a mixin. A mixin class is a class
that provides certain functionality to be inherited by subclasses. They cannot be
instantiated on their own. A mixin class is different from a Java interface in that
the mixin may provide default implementations for its functions and also may
declare and initialize its own variables.
To declare a mixin class in JavaFX, you need to include the mixin keyword in
the class declaration. The following code shows this.

public mixin class Positioner {

A mixin class may contain any number of function declarations. If the function
declaration has a function body, then this is the default implementation for the
function. For example, the following listing shows a mixin class declaration for
a class that positions one node within another.

public mixin class Positioner {


protected bound function centerX(
node: Node, within: Node) : Number {
Clarke.book Page 39 Wednesday, May 6, 2009 10:00 AM

MIXIN CLASSES 39

(within.layoutBounds.width -
node.layoutBounds.width)/2.0 -
node.layoutBounds.minX;
}
protected bound function centerY(node: Node,
within: Node) : Number {
(within.layoutBounds.height -
node.layoutBounds.height)/2.0 -
node.layoutBounds.minY;
}
}

Subclasses that want to implement their own version of the mixin function must
use the override keyword when declaring the function. For instance, the follow-
ing code shows a subclass that implements its own version of the centerX()
function from the Positioner mixin class.

public class My Positioner extends Positioner {


public override bound function centerX(node: Node,
within: Node) : Number {
(within.boundsInParent.width -
node.boundsInParent.width )/2.0;
}
}

If the mixin function does not have a default implementation, it must be declared
abstract and the subclass must override this function to provide an implementa-
tion. For instance, the following code shows an abstract function added to the
Positioner mixin class.

public abstract function bottomY(node: Node,


within: Node, padding: Number) : Number;

The subclass must implement this function using the override keyword, as
shown in the following listing.

public class My Positioner extends Positioner {


public override function bottomY(node: Node,
within: Node, padding: Number) : Number {
within.layoutBounds.height - padding -
node.layoutBounds.height;
}
}

If two mixins have the same function signature or variable name, the system
resolves to the function or variable based on which mixin is declared first in the
Clarke.book Page 40 Wednesday, May 6, 2009 10:00 AM

40 CHAPTER 3 JAVAFX PRIMER

extends clause. To specify a specific function or variable, use the mixin class
name with the function or variable name. This is shown in the following code.

public class My Positioner extends Positioner,


AnotherPositioner {
var offset = 10.0;
public override bound function
centerX(node: Node, within: Node) : Number {
Positioner.centerX(node, within) + offset;
}
}

Mixins may also define variables, with or without default values and triggers.
The subclass either inherits these variables or must override the variable declara-
tion. The following listing demonstrates this.

public mixin class Positioner {


public var offset: Number = 10.0;
}

public class My Positioner extends Positioner {


public override var offset = 5.0 on replace {
println("{offset}");
}
}

If a class extends a JavaFX class and one or more mixins, the JavaFX class takes
precedence over the mixin classes for variable initialization. If the variable is
declared in a superclass, the default value specified in the superclass is used; if
no default value is specified in the superclass, the “default value” for the type of
that variable is used. For the mixin classes, precedence is based on the order they
are defined in the extends clause. If a variable declared in a mixin has a default
value, and the variable is overridden without a default value in the main class, the
initial value specified in the mixin is used.
Mixins may also have init and postinit blocks. Mixin init and postinit blocks
are run after the super class’s init and postinit blocks and before the subclass’s
init and postinit blocks. Init and postinit blocks from the mixin classes
are run in the order they are declared in the extends clause for the subclass.

Object Literals
In JavaFX, objects are instantiated using object literals. This is a declarative syntax
using the name of the class that you want to create, followed by a list of initializ-
Clarke.book Page 41 Wednesday, May 6, 2009 10:00 AM

VARIABLES 41

ers and definitions for this specific instance. In Listing 3.3, an object of class
Title is created with the text “JavaFX is cool” at the screen position 10, 50.
When the mouse is clicked, the provided function will be called.

Listing 3.3 Object Literal


var title = Title {
text: "JavaFX is cool"
x: 10
y: 50
onMouseClicked: function(e:MouseEvent):Void {
// do something
}
};

When declaring an object literal, the instance variables may be separated by


commas or whitespace, as well as the semi-colon.
You can also override abstract functions within the object literal declaration. The
following object literal, shown in Listing 3.4, creates an object for the java.awt
.event.ActionListener interface and overrides the abstract java method void
actionPerformed(ActionEvent e) method.

Listing 3.4 Object Literal – Override Abstract Function


import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

var listener = ActionListener {


override function
actionPerformed(e: ActionEvent) : Void {
println("Action Performed!");
}
}

Variables
JavaFX supports two kinds of variables: instance and script. Script variables
hold state for the entire script, whereas instance variables hold state for specific
instantiations of a class declared within the script file.
Clarke.book Page 42 Wednesday, May 6, 2009 10:00 AM

42 CHAPTER 3 JAVAFX PRIMER

There are basically two flavors of variables: unassignable and changeable.


Unassignable variables are declared using the def keyword and must be assigned
a default value that never changes.

public def PI = 3.14;

These variables cannot be assigned to, overridden, or initialized in object literals.


In a sense, these can be viewed as constants; however, they are not “pure” con-
stants and can participate in binding. (For more information on binding, see
Chapter 4, Synchronize Data Models—Binding and Triggers.)
Consider the following example of defining an unassignable variable that con-
tains an object. The object instance cannot change, but that does not mean the
state of that instance will not.

def centerPoint = Point{x: 100, y:100};


centerPoint.x = 500;

The actual Point object assigned to centerPoint remains unchanged, but the
state of that object instance, the actual x and y values, may change. When used in
binding though, centerPoint is constant; if the state of centerPoint changes,
the bound context will be notified of the change.
Changeable instance variables are declared using the var keyword with an
optional default value. If the default value is omitted, a reasonable default is
used; basically, Numbers default to zero, Boolean defaults to false, Strings
default to the empty string, Sequences default to the Empty Sequence, and
everything else defaults to null.
Script variables are declared outside of any class declaration, whereas instance
variables are declared within a class declaration. If a script variable is declared
with one of the access modifiers—public, protected, or package—it may be
used from outside of the script file, by referring to its fully qualified name. This
fully qualified name is the combination of package name, script name, and the
variable name. The following is the fully qualified name to a public script vari-
able from the javafx.scene.Cursor class for the crosshair cursor.

javafx.scene.Cursor.CROSSHAIR;

Instance variables are declared within a class declaration and come into being
when the object is created. Listing 3.5 illustrates several examples of script and
instance variables.
Clarke.book Page 43 Wednesday, May 6, 2009 10:00 AM

VARIABLES 43

Listing 3.5 Script and Instance Variables


import javafx.scene.Cursor;
import javafx.scene.paint.Color;

// import of script variable from javafx.scene.Cursor


import javafx.scene.Cursor.CROSSHAIR;

// Unchangeable script variable


def defaultText = "Replace ME"; // Script accessible only

// Changeable script variable


public var instanceCount: Integer; // Public accessible

public class Title {


// Unchangeable instance variables
def defStroke = Color.NAVY; // class only access,
//resolves to javafx.scene.paint.Color.NAVY

// Changeable instance variables

// defaults to the empty String ""


public var text:String;
public var width: Number; // defaults to zero (0.0)
public var height = 100; // Infers Integer type
public var stroke: Color = defaultStroke;
public var strokeWidth = 1.0; // Infers Number type
public var cursor = CROSSHAIR;
//resolves to javafx.scene.Cursor.CROSSHAIR

...
}

You may have noticed that some of the declarations contain a type and some
don’t. When a type is not declared, the type is inferred from the first assigned
value. String, Number, Integer, and Boolean are built-in types, everything else
is either a JavaFX or a Java class. (There is a special syntax for easily declaring
Duration and KeyFrame class instances that will be discussed in Chapter 7, Add
Motion with JavaFX Animation.)
Table 3.1 lists the access modifiers for variables and their meaning and restric-
tions. You will notice reference to initialization, which refers to object literal
declarations. Also, you will notice variables being bound. This is a key feature of
JavaFX and is discussed in depth in Chapter 4.
Clarke.book Page 44 Wednesday, May 6, 2009 10:00 AM

44 CHAPTER 3 JAVAFX PRIMER

Table 3.1 Access Modifiers

Access Modifier Meaning

var The default access permission is script access, so without access


modifiers, a variable can be initialized, overridden, read, assigned,
or bound from within the script only.

def The default access permission is script access; a definition can be


read from or bound to within the script only.

public var Read and writable by anyone. Also, it can be initialized, overrid-
den, read, assigned, or bound from anywhere.

public def This definition can be read anywhere. A definition cannot be


assigned, initialized (in an object literal), or overridden no matter
what the access permissions. It may be bound from anywhere.

public-read var Readable by anyone, but only writable within the script.

public-init var Can be initialized in object literals, but can only be updated by the
owning script. Only allowed for instance variables.

package var A variable accessible from the package. This variable can be ini-
tialized, overridden, read, assigned, or bound only from a class
within the same package.

package def Define a variable that is readable or bound only from classes
within the same package.

protected var A variable accessible from the package or subclasses. This vari-
able can be initialized, overridden, read, assigned, or bound from
only a subclass or a class within the same package.

protected def Define a variable that is readable or bound only from classes
within the same package or subclasses.

public-read protected var Readable and bound by anyone, but this variable can only be ini-
tialized, overridden, or assigned from only a subclass or a class
within the same package.

public-init protected var Can be initialized in object literals, read and bound by anyone, but
can only be overridden or assigned, from only a subclass or a
class within the same package. Only allowed for instance
variables.
Clarke.book Page 45 Wednesday, May 6, 2009 10:00 AM

SEQUENCES 45

You can also declare change triggers on a variable. Change triggers are blocks of
JavaFX script that are called whenever the value of a variable changes. To
declare a change trigger, use the on replace syntax:

public var x:Number = 100 on replace {


println("New value is {x}");
};
public var width: Number on replace (old) {
println("Old value is {old}, New value is {x}");
}

Change triggers are discussed in more depth in Chapter 4.

Sequences
Sequences are ordered lists of objects. Because ordered lists are used so often in
programming, JavaFX supports sequence as a first class feature. There is built-in
support in the language for declaring sequences, inserting, deleting, and modify-
ing items in the sequence. There is also powerful support for retrieving items
from the sequence.

Declaring Sequences
To declare a sequence, use square brackets with each item separated by a
comma. For example:

public def monthNames = ["January", "February", "March",


"April", "May", "June",
"July", August", "September",
"October", "November", "December"];

This sequence is a sequence of Strings, because the elements within the brack-
ets are Strings. This could have also been declared as

public def monthNames: String[] = [ "January", .....];

To assign an empty sequence, just use square brackets, []. This is also the
default value for a sequence. For example, the following two statements both
equal the empty sequence.

public var nodes:Node[] = [];

public var nodes:Node[];


Clarke.book Page 46 Wednesday, May 6, 2009 10:00 AM

46 CHAPTER 3 JAVAFX PRIMER

When the sequence changes, you can assign a trigger function to process the
change. This is discussed in depth in the next chapter.
A shorthand for declaring a sequence of Integers and Numbers uses a range, a
start integer or number with an end. So, [1..9] is the sequence of the integers
from 1 thru 9, inclusive; the exclusive form is [1..<9]—that is, 1 through 8. You
can also use a step function, so if, for example, you want even positive integers,
use [2..100 step 2]. For numbers, you can use decimal fractions, [0.1..1.0
step 0.1]. Without the step, a step of 1 or 1.0 is implicit.

Ranges may also go in decreasing order. To do this, the first number must be
higher than the second. However, without a negative step function, you always
end up with an empty sequence. This is because the default step is always posi-
tive 1.

var negativeNumbers = [0..-10]; // Empty sequence


var negativeNumbers = [0..-10 step -1]; // 0,-1,-2,...-10
var negativeNumbers = [0..<-10 step -1]; // 0,-1,-2,...,-9

To build sequences that include the elements from other sequences, just include
the source sequences within the square brackets.

var negativePlusEven = [ negativeNumbers, evenNumbers ];

Also, you can use another sequence to create a sequence by using the Boolean
operator. Another sequence is used as the source, and a Boolean operator is
applied to each element in the source sequence, and the elements from the source
that evaluate to true are returned in the new sequence. In the following example,
n represents each item in the sequence of positive integers and n mod 2 == 0 is
the evaluation.

var evenIntegers = positiveIntegers[n | n mod 2 == 0];

One can also allocate a sequence from a for loop. Each object “returned” from
the iteration of the for loop is added to the sequence:

// creates sequence of Texts


var lineNumbers:Text[] = for(n in [1..100]) {
Text { content: "{n}" };
};

// creates Integer sequence, using indexof operator


var indexNumbers = for(n in nodes) {
indexof n;
};
Clarke.book Page 47 Wednesday, May 6, 2009 10:00 AM

SEQUENCES 47

To get the current size of a sequence use the sizeof operator.

var numEvenNumbers = sizeof evenNumbers;

Accessing Sequence Elements


To access an individual element, use the numeric index of the element within
square brackets:

var firstMonth = monthNames[0];

You can also take slices of sequence by providing a range. Both of the next two
sequences are equal.

var firstQuarter = monthNames[0..2];

var firstQuarter = monthNames[0..<3];

The following two sequences are also equal. The second example uses a syntax
for range to indicate start at an index and return all elements after that index.

var fourthQuarter = monthNames[9..11 ];

var fourthQuarter = monthNames[9.. ];

To iterate over a sequence, use the for loop:

for( month in monthNames) {


println("{month}");
}

Modifying Sequences
To replace an element in a sequence, just assign a new value to that indexed loca-
tion in the index.

var students = [ "joe", "sally", "jim"];


students[0] = "vijay";

Developer Note: As we said at the beginning of this chapter, JavaFX is a forgiv-


ing language, so if you assign to an element index location outside of the existing
size of the sequence, the assignment is silently ignored.
Clarke.book Page 48 Wednesday, May 6, 2009 10:00 AM

48 CHAPTER 3 JAVAFX PRIMER

Let’s use the students sequence from the previous example:

students[3] = "john";

The assignment to position 3 would be ignored because the size of students is cur-
rently 3, and the highest valid index is 2. Similarly, assignment to the index -1 is
silently ignored for the same reason; -1 is outside of the sequence range.
Furthermore, if you access an element location outside of the existing range for the
sequence, a default value is returned. For Numbers, this is zero; for Strings, the
empty string; for Objects, this is null.

To insert an element into the sequence, use the insert statement:

// add "vijay" to the end of students


insert "vijay" into students;

// insert "mike" at the front of students


insert "mike" before students[0];

// insert "george" after the second student


insert "george" after students[1];

To delete an element, use the delete statement:

delete students[0]; // remove the first student


delete students[0..1]; // remove the first 2 students
delete students[0..<2]; // remove the first 2 students
delete students[1..]; // remove all but the first student
delete "vijay" from students;
delete students; // remove all students

Native Array
Native array is a feature that allows you to create Java arrays. This feature is
mainly used to handle the transfer of arrays back and forth from JavaFX and
Java. An example of creating a Java int[] array is shown in the following code.

var ints: nativearray of Integer =


[1,2,3] as nativearray of Integer;

Native arrays are not the same as sequences, though they appear similar. You can-
not use the sequence operators, such as insert and delete, or slices. However, you
can do assignments to the elements of the array as shown in the following code:

ints[2] = 4;
Clarke.book Page 49 Wednesday, May 6, 2009 10:00 AM

FUNCTIONS 49

However, if you assign outside of the current bounds of the array, you will get an
ArrayIndexOutOfBounds Exception.

You can also use the for operator to iterate over the elements in the native array.
The following code shows an example of this.

for(i in ints) {
println(i);
}
for(i in ints where i mod 2 == 0) {
println(i);
}

Functions
Functions define behavior. They encapsulate statements that operate on inputs,
function arguments, and may produce a result, a returned expression. Like vari-
ables, functions are either script functions or instance functions. Script functions
operate at the script level and have access to variables and other functions
defined at the script level. Instance functions define the behavior of an object and
have access to the other instance variables and functions contained within the
function’s declaring class. Furthermore, an instance function may access any
script-level variables and functions contained within its own script file.
To declare a function, use an optional access modifier, public, protected, or
package, followed by the keyword function and the function name. If no
access modifier is provided, the function is private to the script file. Any function
arguments are contained within parentheses. You may then specify a function
return type. If the return type is omitted, the function return type is inferred from
the last expression in the function expression block. The special return type of
Void may be used to indicate that the function returns nothing.

In the following example, both function declarations are equal. The first function
infers a return type of Glow, because the last expression in the function block is
an object literal for a Glow object. The second function explicitly declares a
return type of Glow, and uses the return keyword.

public function glow(level: Number) {


// return type Glow inferred
Glow { level: level };
}

public function glow(): Glow { // explicit return type


return glow(3.0); // explicit return keyword
}
Clarke.book Page 50 Wednesday, May 6, 2009 10:00 AM

50 CHAPTER 3 JAVAFX PRIMER

The return keyword is optional when used as the last expression in a function
block. However, if you want to return immediately out of an if/else or loop,
you must use an explicit return.
In JavaFX, functions are objects in and of themselves and may be assigned to
variables. For example, to declare a function variable, assign a function to that
variable, and then invoke the function through the variable.

var glowFunction : function(level:Number):Glow;


glowFunction = glow;
glowFunction(1.0);

Functions definitions can also be anonymous. For example, for a function variable:

var glowFunction:function(level:Number): Glow =


function(level:Number) {
Glow { level: level };
};

Or, within an object literal declaration:

TextBox {
columns: 20
action: function() {
println("TextBox action");
}
}

Use override to override a function from a superclass.

class MyClass {
public function print() { println("MyClass"); }
}
class MySubClass extends MyClass {
override function print() { println("MySubClass"); }
}

Strings
String Literals
String literals can be specified using either double (") or single (') quotes. The
main reason to use one over the other is to avoid character escapes within the
string literal—for example, if the string literal actually contains double quotes.
Clarke.book Page 51 Wednesday, May 6, 2009 10:00 AM

STRINGS 51

By enclosing the string in single quotes, you do not have to escape the embedded
double quotes. Consider the following two examples, which are both valid:

var quote = "Winston Churchill said:


\"Never in the field of human conflict was
so much owed by so many to so few.\""

var quote = 'Winston Churchill said:


"Never in the field of human conflict was
so much owed by so many to so few."'

Expressions can be embedded within the string literal by using curly braces:

var name = "Jim";


// prints My name is Jim
println ( "My name is {name}" );

The embedded expression must be a valid JavaFX or Java expression that returns
an object. This object will be converted to a string using its toString() method.
For instance:

println ( "Today is {java.util.Date{}}" );

var state ="The state is {


if(running) "Running" else "Stopped"}";

println(" The state is {getStateStr()}" );

println("The state is {
if(checkRunning()) "Running" else "Stopped"}");

Also, a string literal may be split across lines:

var quote = "Winston Churchill said: "


"\"Never in the field of human conflict was so much owed "
"by so many to so few.\"";

In this example, the strings from both lines are concatenated into one string.
Only the string literals within the quotes are used and any white space outside of
the quotes is ignored.
Unicode characters can be entered within the string literal using \u + the four
digit unicode.

var thanks = "dank\u00eb"; // dankë


Clarke.book Page 52 Wednesday, May 6, 2009 10:00 AM

52 CHAPTER 3 JAVAFX PRIMER

Formatting
Embedded expressions within string literals may contain a formatting code that
specifies how the embedded expression should be presented. Consider the
following:

var totalCountMessage = "The total count is {total}";

Now if total is an integer, the resulting string will show the decimal number;
but if total is a Number, the resulting string will show the number formatted
according to the local locale.

var total = 1000.0;

produces:

The total count is 1000.0

To format an expression, you need a format code within the embedded expres-
sion. This is a percent (%) followed by the format codes. The format code is
defined in the java.util.Formatter class. Please refer to its JavaDoc page for
more details (http://java.sun.com/javase/6/docs/api/index.html).

println("Total is {%f total}"); // Total is 1000.000000


println("Total is {%.2f total}"); // Total is 1000.00
println("Total is {%5.0f total}"); // Total is 1000
println("Total is {%+5.0f total}"); // Total is +1000
println("Total is {%,5.0f total}"); // Total is 1,000

Developer Note: To include a percent (%) character in a string, it needs to be


escaped with another percent (%%). For example:
println("%%{percentage}"); // prints %25

Internationalization
To internationalize a string, you must use the “Translate Key” syntax within the
string declaration. To create a translate key, the String assignment starts with ##
(sharp, sharp) combination to indicate that the string is to be translated to the
host locale. The ## combination is before the leading double or single quote.
Optionally, a key may be specified within square brackets ([]). If a key is not
Clarke.book Page 53 Wednesday, May 6, 2009 10:00 AM

STRINGS 53

specified, the string itself becomes the key into the locale properties file. For
example:

var postalCode = ## "Zip Code: ";


var postalCode = ##[postal]"Zip Code: ";

In the preceding example, using the first form, the key is "Zip Code: ", whereas
for the second form, the key is "postal". So how does this work?
By default, the localizer searches for a property file for each unique script name.
This is the package name plus script filename with a locale and a file type of
.fxproperties. So, if your script name is com.mycompany.MyClass, the localizer
code would look for a property file named com/mycompany/MyClass_xx.
fxproperties on the classpath, where xx is the locale. For example, for English
in the United Kingdom, the properties filename would be com/mycompany/
MyClass_en_GB.fxproperties, whereas French Canadian would be com/mycom-
pany/MyClass_fr_CA.fxproperties. If your default locale is just English, the
properties file would be MyClass_en.fxproperties. The more specific file is
searched first, then the least specific file is consulted. For instance, MyClass_
en_GB.fxproperties is searched for the key and if it is not found, then
MyClass_en.fxproperties would be searched. If the key cannot be found at all,
the string itself is used as the default. Here are some examples:

Example #1:
println(##"Thank you");

French – MyClass_fr.fxproperties:

"Thank you" = "Merci"

German – MyClass_de.fxproperties:

"Thank you" = "Danke"

Japanese – MyClass_ja.fxproperties:

"Thank you" = "Arigato"


Clarke.book Page 54 Wednesday, May 6, 2009 10:00 AM

54 CHAPTER 3 JAVAFX PRIMER

Example #2:
println(##[ThankKey] "Thank you");

French – MyClass_fr.fxproperties:

"ThankKey" = "Merci"

German – MyClass_de.fxproperties:

"ThankKey" = "Danke"

Japanese – MyClass_ja.fxproperties:

"ThankKey" = "Arigato"

When you use a string with an embedded expression, the literal key contains a
%s, where the expression is located within the string. For example:

println(##"Hello, my name is {firstname}");

In this case, the key is "Hello, my name is %s". Likewise, if you use more
than one expression, the key contains a "%s" for each expression:

println(##"Hello, my name is {firstname} {lastname}");

Now, the key is "Hello, my name is %s %s".


This parameter substitution is also used in the translated strings. For example:
French – MyClass_fr.fxproperties:

"Hello, my name is %s %s" = "Bonjour, je m'appelle %s %s"

Lastly, you can associate another Properties file to the script. This is done using
the javafx.util.StringLocalizer class. For example:

StringLocalizer.associate("com.mycompany.resources.MyResources",
"com.mycompany");

Now, all translation lookups for scripts in the com.mycompany package will look for
the properties file com/mycompany/resources/MyResources_xx.fxproperties,
instead of using the default that uses the script name. Again, xx is replaced with
the locale abbreviation codes.
Clarke.book Page 55 Wednesday, May 6, 2009 10:00 AM

EXPRESSIONS AND OPERATORS 55

Expressions and Operators


Block Expression
A block expression is a list of statements that may include variable declarations
or other expressions within curly braces. If the last statement is an expression,
the value of a block expression is the value of that last expression; otherwise, the
block expression does not represent a value. Listing 3.6 shows two block expres-
sions. The first expression evaluates to a number represented by the subtotal
value. The second block expression does not evaluate to any value as the last
expression is a println() function that is declared as a Void.

Listing 3.6 Block Expressions


// block expression with a value
var total = {
var subtotal = 0;
var ndx = 0;
while(ndx < 100) {
subtotal += ndx;
ndx++;
};
subtotal; // last expression
};

//block expression without a value


{
var total = 0;
var ndx = 0;
while(ndx < 100) {
total += ndx;
ndx++;
};
println("Total is {total}");
}

Exception Handling
The throw statement is the same as Java and can only throw a class that extends
java.lang.Throwable.

The try/catch/finally expression is the same as Java, but uses the JavaFX syntax:

try {
} catch (e:SomeException) {
} finally {
}
Clarke.book Page 56 Wednesday, May 6, 2009 10:00 AM

56 CHAPTER 3 JAVAFX PRIMER

Operators
Table 3.2 contains a list of the operators used in JavaFX. The priority column
indicates the operator evaluation precedence, with higher precedence operators
in the first rows. Operators with the same precedence level are evaluated equally.
Assignment operators are evaluated right to left, whereas all others are evaluated
left to right. Parentheses may be used to alter this default evaluation order.

Table 3.2 Operators

Priority Operator Meaning

1 ++/-- (Suffixed) Post-increment/decrement assignment

2 ++/-- (Prefixed) Pre-increment/decrement assignment

- Unary minus

not Logical complement; inverts value of a Boolean

sizeof Size of a sequence

reverse Reverse sequence order

indexof Index of a sequence element

3 /, *, mod Arithmetic operators

4 +, - Arithmetic operators

5 ==, != Comparison operators (Note: all comparisons are similar to


isEquals() in Java)

<, <=, >, >= Numeric comparison operators

6 instanceof, as Type operators

7 and Logical AND

8 or Logical OR

9 +=, -=, *=, /= Compound assignment

10 =>, tween Animation interpolation operators

11 = Assignment
Clarke.book Page 57 Wednesday, May 6, 2009 10:00 AM

EXPRESSIONS AND OPERATORS 57

Conditional Expressions
if/else
if is similar to if as defined in other languages. First, a condition is evaluated
and if true, the expression block is evaluated. Otherwise, if an else expression
block is provided, that expression block is evaluated.

if (date == today) {
println("Date is today");
}else {
println("Out of date!!!");
}

One important feature of if/else is that each expression block may evaluate to
an expression that may be assigned to a variable:

var outOfDateMessage = if(date==today) "Date is today"


else "Out of Date";

Also the expression blocks can be more complex than simple expressions. List-
ing 3.7 shows a complex assignment using an if/else statement to assign the
value to outOfDateMessage.

Listing 3.7 Complex Assignment Using if/else Expression


var outOfDateMessage = if(date==today) {
var total = 0;
for(item in items) {
total += items.price;
}
totalPrice += total;
"Date is today";
} else {
errorFlag = true;
"Out of Date";
};

In the previous example, the last expression in the block, the error message string
literal, is the object that is assigned to the variable. This can be any JavaFX
Object, including numbers.
Because the if/else is an expression block, it can be used with another if/else
statement. For example:
Clarke.book Page 58 Wednesday, May 6, 2009 10:00 AM

58 CHAPTER 3 JAVAFX PRIMER

var taxBracket = if(income < 8025.0) 0.10


else if(income < 32550.0)0.15
else if (income < 78850.0) 0.25
else if (income < 164550.0) 0.28
else 0.33;

Looping Expressions
For
for loops are used with sequences and allow you to iterate over the members of
a sequence.

var daysOfWeek : String[] =


[ "Sunday", "Monday", "Tuesday" ];
for(day in daysOfWeek) {
println("{indexof day}). {day}");
}

To be similar with traditional for loops that iterate over a count, use an integer
sequence range defined within square brackets.

for( i in [0..100]} {

The for expression can also return a new sequence. For each iteration, if the
expression block executed evaluates to an Object, that Object is inserted into a
new sequence returned by the for expression. For example, in the following for
expression, a new Text node is created with each iteration of the day of the
week. The overall for expression returns a new sequence containing Text graph-
ical elements, one for each day of the week.

var textNodes: Text[] = for( day in daysOfWeek) {


Text {content: day };
}

Another feature of the for expression is that it can do nested loops. Listing 3.8
shows an example of using nested loops.

Listing 3.8 Nested For Loop


class Course {
var title: String;
var students: String[];
}
var courses = [
Clarke.book Page 59 Wednesday, May 6, 2009 10:00 AM

EXPRESSIONS AND OPERATORS 59

Course {
title: "Geometry I"
students: [ "Clarke, "Connors", "Bruno" ]
},
Course {
title: "Geometry II"
students: [ "Clarke, "Connors", ]
},
Course {
title: "Algebra I"
students: [ "Connors", "Bruno" ]
},
];

for(course in courses, student in course.students) {


println("Student: {student} is in course {course}");
}

This prints out:

Student: Clarke is in course Geometry I


Student: Connors is in course Geometry I
Student: Bruno is in course Geometry I
Student: Clarke is in course Geometry II
Student: Connors is in course Geometry II
Student: Connors is in course Algebra I
Student: Bruno is in course Algebra I

There may be zero or more secondary loops and they are separated from the pre-
vious ones by a comma, and may reference any element from the previous loops.
You can also include a where clause on the sequence to limit the iteration to only
those elements where the where clause evaluates to true:

var evenNumbers = for( i in [0..1000] where i mod 2 == 0 ) i;

while
The while loop works similar to the while loop as seen in other languages:

var ndx = 0;
while ( ndx < 100) {
println("{ndx}");
ndx++;
}

Note that unlike the JavaFX for loop, the while loop does not return any expres-
sion, so it cannot be used to create a sequence.
Clarke.book Page 60 Wednesday, May 6, 2009 10:00 AM

60 CHAPTER 3 JAVAFX PRIMER

Break/Continue
break and continue control loop iterations. break is used to quit the loop altogether.
It causes all the looping to stop from that point. On the other hand, continue just
causes the current iteration to stop, and the loop resumes with the next iteration.
Listing 3.9 demonstrates how these are used.

Listing 3.9 Break/Continue


for(student in students) {
if(student.name == "Jim") {
foundStudent = student;
break; // stops the loop altogether,
//no more students are checked
}
}

for(book in Books ) {
if(book.publisher == "Addison Wesley") {
insert book into bookList;
continue; // moves on to check next book.
}
insert book into otherBookList;
otherPrice += book.price;
}

Type Operators
The instanceof operator allows you to test the class type of an object, whereas
the as operator allows you to cast an object to another class. One way this is use-
ful is to cast a generalized object to a more specific class in order to perform a
function from that more specialized class. Of course, the object must inherently
be that kind of class, and that is where the instanceof operator is useful to test
if the object is indeed that kind of class. If you try to cast an object to a class that
that object does not inherit from, you will get an exception.
In the following listing, the printLower() function will translate a string to lower-
case, but for other types of objects, it will just print it as is. First, the generic object
is tested to see if it is a String. If it is, the object is cast to a String using the as oper-
ator, and then the String’s toLowerCase() method is used to convert the output to
all lowercase. Listing 3.10 illustrates the use of the instanceof and as operators.

Listing 3.10 Type Operators


function printLower(object: Object ) {
if(object instanceof String) {
Clarke.book Page 61 Wednesday, May 6, 2009 10:00 AM

EXPRESSIONS AND OPERATORS 61

var str = object as String;


println(str.toLowerCase());
}else {
println(object);
}

}
printLower("Rich Internet Application");
printLower(3.14);

Accessing Command-Line Arguments


For a pure script that does not declare exported classes, variables, or functions,
the command-line arguments can be retrieved using the javafx.lang.FX
.getArguments():String[] function. This returns a Sequence of Strings that
contains the arguments passed to the script when it started. There is a another
version of this for use in other invocations, such as applets, where the arguments
are passed using name value pairs, javafx.lang.FX.getArguments(key:String)
:String[]. Similarly, there is a function to get system properties, javafx.lang.FX
.getProperty(key:String):String[].

If the script contains any exported classes, variables, or functions, arguments are
obtained by defining a special run function at the script level.

public function run(args:String[] ) {


for(arg in args) {
println("{arg}");
}
}

Loose Expressions with Exported Members: Variables, functions, and expres-


sions at the script level (not within a class declaration) are called loose expressions.
When these variables and functions are private to the script, no specific run func-
tion is required if the script is executed from the command line. However, if any of
these expressions are exported outside of the script using public, public-read, pro-
tected, package access, a run function is required if the script is to be executed
directly. This run method encapsulates the exported variables and functions.

Built-in Functions and Variables


There are a set of functions that are automatically available to all JavaFX scripts.
These functions are defined in javafx.lang.Builtins.
Clarke.book Page 62 Wednesday, May 6, 2009 10:00 AM

62 CHAPTER 3 JAVAFX PRIMER

You have already seen one of these, println(). Println() takes an object argu-
ment and prints it out to the console, one line at a time. It is similar to the Java
method, System.out.println(). Its companion function is print(). Print()
prints out its argument but without a new line. The argument’s toString()
method is invoked to print out a string.

println("This is printed on a single line");


print("This is printed without a new line");

Another function from javafx.lang.Builtins is isInitialized(). This method


takes a JavaFX object and indicates whether the object has been completely ini-
tialized. It is useful in variable triggers to determine the current state of the
object during initialization. There may be times that you want to execute some
functionality only after the object has passed the initialization stage. For exam-
ple, Listing 3.11 shows the built-in, isInitialized() being used in an on
replace trigger.

Listing 3.11 isInitialized()


public class Test {
public var status: Number on replace {
// will not be initialized
// until status is assigned a value
if(isInitialized(status)) {

commenceTest(status);
}
}
public function commenceTest(status:Number) : Void {
println("commenceTest status = {status}:);
}
}

In this example, when the class, Test, is first instantiated, the instance variable,
status, first takes on the default value of 0.0, and then the on replace expression
block is evaluated. However, this leaves the status in the uninitialized state.
Only when a value is assigned to status, will the state change to initialized.
Consider the following:

var test = Test{}; // status is uninitialized


test.status = 1; // now status becomes initialized

In this case when Test is created using the object literal, Test{}, status takes on
the default value of 0.0; however, it is not initialized, so commenceTest will
Clarke.book Page 63 Wednesday, May 6, 2009 10:00 AM

EXPRESSIONS AND OPERATORS 63

not be invoked during object creation. Now when we assign a value to status,
the state changes to initialized, so commenceTest is now invoked. Please note
that if we had assigned a default value to status, even if that value is 0, then
status immediately is set to initialized. The following example demon-
strates this.

public class Test {


public var status: Number = 0 on replace {
// will be initialized immediately.
if(isInitialized(status)) {
commenceTest(status);
}
}

The last built-in function is isSameObject(). isSameObject() indicates if the


two arguments actually are the same instance. This is opposed to the == operator.
In JavaFX, the == operator determines whether two objects are considered equal,
but that does not mean they are the same instance. The == operator is similar to
the Java function isEquals(), whereas JavaFX isSameObject is similar to the
Java == operator. A little confusing if your background is Java!
The built-in variables are __DIR__ and __FILE__. __FILE__ holds the resource
URL string for the containing JavaFX class. __DIR__ holds the resource URL
string for directory that contains the current class. For example,

println("DIR = {__DIR__}");
println("FILE = {__FILE__}");
// to locate an image
var image = Image { url: "{__DIR__}images/foo.jpeg" };

The following examples show the output from a directory based classpath versus
using a JAR-based class path.

Using a Jar file in classpath


$javafx -cp Misc.jar misc.Test

DIR = jar:file:/export/home/jclarke/Documents/
Book/FX/code/Chapter3/Misc/dist/Misc.jar!/misc/

FILE = jar:file:/export/home/jclarke/Documents/
Book/FX/code/Chapter3/Misc/dist/Misc.jar!/misc/Test.class
continues
Clarke.book Page 64 Wednesday, May 6, 2009 10:00 AM

64 CHAPTER 3 JAVAFX PRIMER

Using directory classpath


$ javafx -cp . misc.Test

DIR = file:/export/home/jclarke/Documents/Book/
FX/code/Chapter3/Misc/dist/tmp/misc/

FILE = file:/export/home/jclarke/Documents/Book/
FX/code/Chapter3/Misc/dist/tmp/misc/Test.class

Notice the Trailing Slash on __DIR__: Because the tailing slash already exists
on __DIR__, do not add an extra trailing slash when using __DIR__ to build a path to
a resource like an image. Image{ url: "{__DIR__}image/foo.jpeg"} is correct.
Image{ url: "{__DIR__}/image/foo.jpeg"} is wrong. If you add the trailing slash
after __DIR__, the image will not be found and you will be scratching your head
trying to figure out why not.

Chapter Summary
This chapter covered key concepts in the JavaFX Scripting language. You were
shown what constitutes a script and what constitutes a class. You were shown
how to declare script and instance variables, how to create and modify
sequences, and how to control logic flow.
You now have a basic understanding of the JavaFX Script language syntax and
operators. Now, it is time to put this to use. In the following chapters, we will
drill down into the key features of JavaFX and show how to leverage the JavaFX
Script language to take advantage of those features. In the next chapter, we start
our exploration of JavaFX by discussing the data synchronization support in the
JavaFX runtime.
Google
Bookmarks Delicious Digg Facebook StumbleUpon Reddit Twitter

Java_Rock_Star_CH_Openers copy.indd 9 6/18/09 11:56:37 AM


Brian Goetz
Tim Peierls
Joshua Bloch
Joseph Bowbeer
David Holmes
Doug Lea

Java Concurrency in Practice


Threads are a fundamental part of the Java platform. As multicore processors become
the norm, using concurrency effectively becomes essential for building high-perfor-
mance applications. Java SE 5 and 6 are a huge step forward for the development of
concurrent applications, with improvements to the Java Virtual Machine to support AVAILABLE
high-performance, highly scalable concurrent classes and a rich set of new concurrency • BOOK: 9780321349606
building blocks. In Java Concurrency in Practice, the creators of these new facilities • SAFARI ONLINE
explain not only how they work and how to use them, but also the motivation and design
• EBOOK: 0321467833
patterns behind them.
• KINDLE: 0768665132
However, developing, testing, and debugging multithreaded programs can still be
very difficult; it is all too easy to create concurrent programs that appear to work, but
fail when it matters most: in production, under heavy load. Java Concurrency in
Practice arms readers with both the theoretical underpinnings and concrete techniques About the Authors
for building reliable, scalable, maintainable concurrent applications. Rather than simply (cont’d)
offering an inventory of concurrency APIs and mechanisms, it provides design rules, David Holmes is director of DLTeCH
patterns, and mental models that make it easier to build concurrent programs that are Pty Ltd, located in Brisbane, Australia.
both correct and performant. He specializes in synchronization and
This book covers: concurrency and was a member of the
JSR-166 expert group that developed the
• Basic concepts of concurrency and thread safety new concurrency utilities. He is also a
• Techniques for building and composing thread-safe classes contributor to the update of the Real-Time
• Using the concurrency building blocks in java.util.concurrent Specification for Java, and has spent the
past few years working on an implementa-
• Performance optimization dos and don’ts tion of that specification.
• Testing concurrent programs Doug Lea is one of the foremost
• Advanced topics such as atomic variables, nonblocking algorithms, and the experts on object-oriented technology
Java Memory Model and software reuse. He has been doing
collaborative research with Sun Labs for
more than five years. Lea is Professor
About the Authors of Computer Science at SUNY Oswego,
Brian Goetz is a software consultant with twenty years industry experience, with over 75 articles Co-director of the Software Engineering
on Java development. He is one of the primary members of the Java Community Process JSR 166 Lab at the New York Center for Advanced
Expert Group (Concurrency Utilities), and has served on numerous other JCP Expert Groups. Technology in Computer Applications,
and Adjunct Professor of Electrical and
Tim Peierls is the very model of a modern multiprocessor, with BoxPop.biz, recording arts, and
Computer Engineering at Syracuse
goings on theatrical. He is one of the primary members of the Java Community Process JSR 166
University. In addition, he co-authored
Expert Group (Concurrency Utilities), and has served on numerous other JCP Expert Groups.
the book, Object-Oriented System
Joshua Bloch is a principal engineer at Google and a Jolt Award-winner. He was previously a Development (Addison-Wesley, 1993). He
distinguished engineer at Sun Microsystems and a senior systems designer at Transarc. Josh led received his B.A., M.A., and Ph.D. from
the design and implementation of numerous Java platform features, including JDK 5.0 language the University of New Hampshire.
enhancements and the award-winning Java Collections Framework. He holds a Ph.D. in computer
science from Carnegie Mellon University.
Joseph Bowbeer is a software architect at Vizrea Corporation where he specializes in mobile
application development for the Java ME platform, but his fascination with concurrent programming
began in his days at Apollo Computer. He served on the JCP Expert Group for JSR-166 (Concur-
rency Utilities).

informit.com/aw

Java_Rock_Star_CH_Openers copy.indd 10 6/18/09 11:56:38 AM


Chapter 6

Task Execution

Most concurrent applications are organized around the execution of tasks: ab-
stract, discrete units of work. Dividing the work of an application into tasks
simplifies program organization, facilitates error recovery by providing natural
transaction boundaries, and promotes concurrency by providing a natural struc-
ture for parallelizing work.

6.1 Executing tasks in threads


The first step in organizing a program around task execution is identifying sen-
sible task boundaries. Ideally, tasks are independent activities: work that doesn’t
depend on the state, result, or side effects of other tasks. Independence facili-
tates concurrency, as independent tasks can be executed in parallel if there are
adequate processing resources. For greater flexibility in scheduling and load bal-
ancing tasks, each task should also represent a small fraction of your application’s
processing capacity.
Server applications should exhibit both good throughput and good responsiveness
under normal load. Application providers want applications to support as many
users as possible, so as to reduce provisioning costs per user; users want to get
their response quickly. Further, applications should exhibit graceful degradation
as they become overloaded, rather than simply falling over under heavy load.
Choosing good task boundaries, coupled with a sensible task execution policy (see
Section 6.2.2), can help achieve these goals.
Most server applications offer a natural choice of task boundary: individual
client requests. Web servers, mail servers, file servers, EJB containers, and da-
tabase servers all accept requests via network connections from remote clients.
Using individual requests as task boundaries usually offers both independence
and appropriate task sizing. For example, the result of submitting a message to
a mail server is not affected by the other messages being processed at the same
time, and handling a single message usually requires a very small percentage of
the server’s total capacity.

113
114 Chapter 6. Task Execution

6.1.1 Executing tasks sequentially


There are a number of possible policies for scheduling tasks within an applica-
tion, some of which exploit the potential for concurrency better than others. The
simplest is to execute tasks sequentially in a single thread. SingleThreadWeb-
Server in Listing 6.1 processes its tasks—HTTP requests arriving on port 80—
sequentially. The details of the request processing aren’t important; we’re inter-
ested in characterizing the concurrency of various scheduling policies.

class SingleThreadWebServer {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(80);
while (true) {
Socket connection = socket.accept();
handleRequest(connection);
}
}
}

Listing 6.1. Sequential web server.

SingleThreadedWebServer is simple and theoretically correct, but would per-


form poorly in production because it can handle only one request at a time. The
main thread alternates between accepting connections and processing the associ-
ated request. While the server is handling a request, new connections must wait
until it finishes the current request and calls accept again. This might work if
request processing were so fast that handleRequest effectively returned immedi-
ately, but this doesn’t describe any web server in the real world.
Processing a web request involves a mix of computation and I/O. The server
must perform socket I/O to read the request and write the response, which can
block due to network congestion or connectivity problems. It may also perform
file I/O or make database requests, which can also block. In a single-threaded
server, blocking not only delays completing the current request, but prevents
pending requests from being processed at all. If one request blocks for an un-
usually long time, users might think the server is unavailable because it appears
unresponsive. At the same time, resource utilization is poor, since the CPU sits
idle while the single thread waits for its I/O to complete.
In server applications, sequential processing rarely provides either good
throughput or good responsiveness. There are exceptions—such as when tasks
are few and long-lived, or when the server serves a single client that makes only
a single request at a time—but most server applications do not work this way.1

1. In some situations, sequential processing may offer a simplicity or safety advantage; most GUI
frameworks process tasks sequentially using a single thread. We return to the sequential model in
Chapter 9.
6.1. Executing tasks in threads 115

6.1.2 Explicitly creating threads for tasks


A more responsive approach is to create a new thread for servicing each request,
as shown in ThreadPerTaskWebServer in Listing 6.2.

class ThreadPerTaskWebServer {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(80);
while (true) {
final Socket connection = socket.accept();
Runnable task = new Runnable() {
public void run() {
handleRequest(connection);
}
};
new Thread(task).start();
}
}
}

Listing 6.2. Web server that starts a new thread for each request.

ThreadPerTaskWebServer is similar in structure to the single-threaded


version—the main thread still alternates between accepting an incoming con-
nection and dispatching the request. The difference is that for each connection,
the main loop creates a new thread to process the request instead of processing it
within the main thread. This has three main consequences:

• Task processing is offloaded from the main thread, enabling the main loop
to resume waiting for the next incoming connection more quickly. This
enables new connections to be accepted before previous requests complete,
improving responsiveness.
• Tasks can be processed in parallel, enabling multiple requests to be serviced
simultaneously. This may improve throughput if there are multiple process-
ors, or if tasks need to block for any reason such as I/O completion, lock
acquisition, or resource availability.

• Task-handling code must be thread-safe, because it may be invoked concur-


rently for multiple tasks.

Under light to moderate load, the thread-per-task approach is an improvement


over sequential execution. As long as the request arrival rate does not exceed the
server’s capacity to handle requests, this approach offers better responsiveness
and throughput.
116 Chapter 6. Task Execution

6.1.3 Disadvantages of unbounded thread creation


For production use, however, the thread-per-task approach has some practical
drawbacks, especially when a large number of threads may be created:

Thread lifecycle overhead. Thread creation and teardown are not free. The ac-
tual overhead varies across platforms, but thread creation takes time, intro-
ducing latency into request processing, and requires some processing activ-
ity by the JVM and OS. If requests are frequent and lightweight, as in most
server applications, creating a new thread for each request can consume
significant computing resources.
Resource consumption. Active threads consume system resources, especially
memory. When there are more runnable threads than available process-
ors, threads sit idle. Having many idle threads can tie up a lot of memory,
putting pressure on the garbage collector, and having many threads com-
peting for the CPUs can impose other performance costs as well. If you have
enough threads to keep all the CPUs busy, creating more threads won’t help
and may even hurt.
Stability. There is a limit on how many threads can be created. The limit varies
by platform and is affected by factors including JVM invocation parameters,
the requested stack size in the Thread constructor, and limits on threads
placed by the underlying operating system.2 When you hit this limit, the
most likely result is an OutOfMemoryError. Trying to recover from such an
error is very risky; it is far easier to structure your program to avoid hitting
this limit.

Up to a certain point, more threads can improve throughput, but beyond that
point creating more threads just slows down your application, and creating one
thread too many can cause your entire application to crash horribly. The way to
stay out of danger is to place some bound on how many threads your application
creates, and to test your application thoroughly to ensure that, even when this
bound is reached, it does not run out of resources.
The problem with the thread-per-task approach is that nothing places any
limit on the number of threads created except the rate at which remote users can
throw HTTP requests at it. Like other concurrency hazards, unbounded thread
creation may appear to work just fine during prototyping and development, with
problems surfacing only when the application is deployed and under heavy load.
So a malicious user, or enough ordinary users, can make your web server crash
if the traffic load ever reaches a certain threshold. For a server application that is
supposed to provide high availability and graceful degradation under load, this
is a serious failing.

2. On 32-bit machines, a major limiting factor is address space for thread stacks. Each thread main-
tains two execution stacks, one for Java code and one for native code. Typical JVM defaults yield
a combined stack size of around half a megabyte. (You can change this with the -Xss JVM flag or
through the Thread constructor.) If you divide the per-thread stack size into 232 , you get a limit of
a few thousands or tens of thousands of threads. Other factors, such as OS limitations, may impose
stricter limits.
6.2. The Executor framework 117

6.2 The Executor framework


Tasks are logical units of work, and threads are a mechanism by which tasks
can run asynchronously. We’ve examined two policies for executing tasks using
threads—execute tasks sequentially in a single thread, and execute each task in its
own thread. Both have serious limitations: the sequential approach suffers from
poor responsiveness and throughput, and the thread-per-task approach suffers
from poor resource management.
In Chapter 5, we saw how to use bounded queues to prevent an overloaded
application from running out of memory. Thread pools offer the same benefit for
thread management, and java.util.concurrent provides a flexible thread pool
implementation as part of the Executor framework. The primary abstraction for
task execution in the Java class libraries is not Thread, but Executor, shown in
Listing 6.3.

public interface Executor {


void execute(Runnable command);
}

Listing 6.3. Executor interface.

Executor may be a simple interface, but it forms the basis for a flexible and
powerful framework for asynchronous task execution that supports a wide vari-
ety of task execution policies. It provides a standard means of decoupling task
submission from task execution, describing tasks with Runnable. The Executor
implementations also provide lifecycle support and hooks for adding statistics
gathering, application management, and monitoring.
Executor is based on the producer-consumer pattern, where activities that
submit tasks are the producers (producing units of work to be done) and the
threads that execute tasks are the consumers (consuming those units of work).
Using an Executor is usually the easiest path to implementing a producer-consumer
design in your application.

6.2.1 Example: web server using Executor


Building a web server with an Executor is easy. TaskExecutionWebServer in
Listing 6.4 replaces the hard-coded thread creation with an Executor. In this
case, we use one of the standard Executor implementations, a fixed-size thread
pool with 100 threads.
In TaskExecutionWebServer, submission of the request-handling task is de-
coupled from its execution using an Executor, and its behavior can be changed
merely by substituting a different Executor implementation. Changing Executor
implementations or configuration is far less invasive than changing the way tasks
are submitted; Executor configuration is generally a one-time event and can eas-
ily be exposed for deployment-time configuration, whereas task submission code
tends to be strewn throughout the program and harder to expose.
118 Chapter 6. Task Execution

class TaskExecutionWebServer {
private static final int NTHREADS = 100;
private static final Executor exec
= Executors.newFixedThreadPool(NTHREADS);

public static void main(String[] args) throws IOException {


ServerSocket socket = new ServerSocket(80);
while (true) {
final Socket connection = socket.accept();
Runnable task = new Runnable() {
public void run() {
handleRequest(connection);
}
};
exec.execute(task);
}
}
}

Listing 6.4. Web server using a thread pool.

We can easily modify TaskExecutionWebServer to behave like ThreadPer-


TaskWebServer by substituting an Executor that creates a new thread for each
request. Writing such an Executor is trivial, as shown in ThreadPerTaskExecut-
or in Listing 6.5.

public class ThreadPerTaskExecutor implements Executor {


public void execute(Runnable r) {
new Thread(r).start();
};
}

Listing 6.5. Executor that starts a new thread for each task.

Similarly, it is also easy to write an Executor that would make TaskExecut-


ionWebServer behave like the single-threaded version, executing each task syn-
chronously before returning from execute, as shown in WithinThreadExecutor
in Listing 6.6.

6.2.2 Execution policies


The value of decoupling submission from execution is that it lets you easily spec-
ify, and subsequently change without great difficulty, the execution policy for a
given class of tasks. An execution policy specifies the “what, where, when, and
how” of task execution, including:
6.2. The Executor framework 119

public class WithinThreadExecutor implements Executor {


public void execute(Runnable r) {
r.run();
};
}

Listing 6.6. Executor that executes tasks synchronously in the calling thread.

• In what thread will tasks be executed?

• In what order should tasks be executed (FIFO, LIFO, priority order)?


• How many tasks may execute concurrently?
• How many tasks may be queued pending execution?
• If a task has to be rejected because the system is overloaded, which task
should be selected as the victim, and how should the application be noti-
fied?
• What actions should be taken before or after executing a task?

Execution policies are a resource management tool, and the optimal policy
depends on the available computing resources and your quality-of-service re-
quirements. By limiting the number of concurrent tasks, you can ensure that
the application does not fail due to resource exhaustion or suffer performance
problems due to contention for scarce resources.3 Separating the specification of
execution policy from task submission makes it practical to select an execution
policy at deployment time that is matched to the available hardware.

Whenever you see code of the form:


new Thread(runnable).start()
and you think you might at some point want a more flexible execution
policy, seriously consider replacing it with the use of an Executor.

6.2.3 Thread pools


A thread pool, as its name suggests, manages a homogeneous pool of worker
threads. A thread pool is tightly bound to a work queue holding tasks waiting to
be executed. Worker threads have a simple life: request the next task from the
work queue, execute it, and go back to waiting for another task.

3. This is analogous to one of the roles of a transaction monitor in an enterprise application: it can
throttle the rate at which transactions are allowed to proceed so as not to exhaust or overstress limited
resources.
120 Chapter 6. Task Execution

Executing tasks in pool threads has a number of advantages over the thread-
per-task approach. Reusing an existing thread instead of creating a new one
amortizes thread creation and teardown costs over multiple requests. As an
added bonus, since the worker thread often already exists at the time the request
arrives, the latency associated with thread creation does not delay task execution,
thus improving responsiveness. By properly tuning the size of the thread pool,
you can have enough threads to keep the processors busy while not having so
many that your application runs out of memory or thrashes due to competition
among threads for resources.
The class library provides a flexible thread pool implementation along with
some useful predefined configurations. You can create a thread pool by calling
one of the static factory methods in Executors:

newFixedThreadPool. A fixed-size thread pool creates threads as tasks are sub-


mitted, up to the maximum pool size, and then attempts to keep the pool
size constant (adding new threads if a thread dies due to an unexpected
Exception).

newCachedThreadPool. A cached thread pool has more flexibility to reap idle


threads when the current size of the pool exceeds the demand for process-
ing, and to add new threads when demand increases, but places no bounds
on the size of the pool.

newSingleThreadExecutor. A single-threaded executor creates a single worker


thread to process tasks, replacing it if it dies unexpectedly. Tasks are guar-
anteed to be processed sequentially according to the order imposed by the
task queue (FIFO, LIFO, priority order).4

newScheduledThreadPool. A fixed-size thread pool that supports delayed and


periodic task execution, similar to Timer. (See Section 6.2.5.)

The newFixedThreadPool and newCachedThreadPool factories return in-


stances of the general-purpose ThreadPoolExecutor, which can also be used
directly to construct more specialized executors. We discuss thread pool configu-
ration options in depth in Chapter 8.
The web server in TaskExecutionWebServer uses an Executor with a bounded
pool of worker threads. Submitting a task with execute adds the task to the work
queue, and the worker threads repeatedly dequeue tasks from the work queue
and execute them.
Switching from a thread-per-task policy to a pool-based policy has a big effect
on application stability: the web server will no longer fail under heavy load.5

4. Single-threaded executors also provide sufficient internal synchronization to guarantee that any
memory writes made by tasks are visible to subsequent tasks; this means that objects can be safely
confined to the “task thread” even though that thread may be replaced with another from time to
time.
5. While the server may not fail due to the creation of too many threads, if the task arrival rate exceeds
the task service rate for long enough it is still possible (just harder) to run out of memory because
of the growing queue of Runnables awaiting execution. This can be addressed within the Executor
framework by using a bounded work queue—see Section 8.3.2.
6.2. The Executor framework 121

It also degrades more gracefully, since it does not create thousands of threads
that compete for limited CPU and memory resources. And using an Executor
opens the door to all sorts of additional opportunities for tuning, management,
monitoring, logging, error reporting, and other possibilities that would have been
far more difficult to add without a task execution framework.

6.2.4 Executor lifecycle


We’ve seen how to create an Executor but not how to shut one down. An Exec-
utor implementation is likely to create threads for processing tasks. But the JVM
can’t exit until all the (nondaemon) threads have terminated, so failing to shut
down an Executor could prevent the JVM from exiting.
Because an Executor processes tasks asynchronously, at any given time the
state of previously submitted tasks is not immediately obvious. Some may have
completed, some may be currently running, and others may be queued awaiting
execution. In shutting down an application, there is a spectrum from graceful
shutdown (finish what you’ve started but don’t accept any new work) to abrupt
shutdown (turn off the power to the machine room), and various points in be-
tween. Since Executors provide a service to applications, they should be able to
be shut down as well, both gracefully and abruptly, and feed back information to
the application about the status of tasks that were affected by the shutdown.
To address the issue of execution service lifecycle, the ExecutorService in-
terface extends Executor, adding a number of methods for lifecycle management
(as well as some convenience methods for task submission). The lifecycle man-
agement methods of ExecutorService are shown in Listing 6.7.

public interface ExecutorService extends Executor {


void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
// ... additional convenience methods for task submission
}

Listing 6.7. Lifecycle methods in ExecutorService.

The lifecycle implied by ExecutorService has three states—running, shutting


down, and terminated. ExecutorServices are initially created in the running state.
The shutdown method initiates a graceful shutdown: no new tasks are accepted
but previously submitted tasks are allowed to complete—including those that
have not yet begun execution. The shutdownNow method initiates an abrupt shut-
down: it attempts to cancel outstanding tasks and does not start any tasks that
are queued but not begun.
Tasks submitted to an ExecutorService after it has been shut down are han-
dled by the rejected execution handler (see Section 8.3.3), which might silently dis-
122 Chapter 6. Task Execution

card the task or might cause execute to throw the unchecked RejectedExecu-
tionException. Once all tasks have completed, the ExecutorService transitions
to the terminated state. You can wait for an ExecutorService to reach the termi-
nated state with awaitTermination, or poll for whether it has yet terminated with
isTerminated. It is common to follow shutdown immediately by awaitTermina-
tion, creating the effect of synchronously shutting down the ExecutorService.
(Executor shutdown and task cancellation are covered in more detail in Chapter
7.)
LifecycleWebServer in Listing 6.8 extends our web server with lifecycle sup-
port. It can be shut down in two ways: programmatically by calling stop, and
through a client request by sending the web server a specially formatted HTTP
request.

class LifecycleWebServer {
private final ExecutorService exec = ...;

public void start() throws IOException {


ServerSocket socket = new ServerSocket(80);
while (!exec.isShutdown()) {
try {
final Socket conn = socket.accept();
exec.execute(new Runnable() {
public void run() { handleRequest(conn); }
});
} catch (RejectedExecutionException e) {
if (!exec.isShutdown())
log("task submission rejected", e);
}
}
}

public void stop() { exec.shutdown(); }

void handleRequest(Socket connection) {


Request req = readRequest(connection);
if (isShutdownRequest(req))
stop();
else
dispatchRequest(req);
}
}

Listing 6.8. Web server with shutdown support.


6.3. Finding exploitable parallelism 123

6.2.5 Delayed and periodic tasks


The Timer facility manages the execution of deferred (“run this task in 100 ms”)
and periodic (“run this task every 10 ms”) tasks. However, Timer has some draw-
backs, and ScheduledThreadPoolExecutor should be thought of as its replace-
ment.6 You can construct a ScheduledThreadPoolExecutor through its construc-
tor or through the newScheduledThreadPool factory.
A Timer creates only a single thread for executing timer tasks. If a timer
task takes too long to run, the timing accuracy of other TimerTasks can suffer.
If a recurring TimerTask is scheduled to run every 10 ms and another Timer-
Task takes 40 ms to run, the recurring task either (depending on whether it was
scheduled at fixed rate or fixed delay) gets called four times in rapid succession
after the long-running task completes, or “misses” four invocations completely.
Scheduled thread pools address this limitation by letting you provide multiple
threads for executing deferred and periodic tasks.
Another problem with Timer is that it behaves poorly if a TimerTask throws
an unchecked exception. The Timer thread doesn’t catch the exception, so an un-
checked exception thrown from a TimerTask terminates the timer thread. Timer
also doesn’t resurrect the thread in this situation; instead, it erroneously assumes
the entire Timer was cancelled. In this case, TimerTasks that are already sched-
uled but not yet executed are never run, and new tasks cannot be scheduled.
(This problem, called “thread leakage” is described in Section 7.3, along with
techniques for avoiding it.)
OutOfTime in Listing 6.9 illustrates how a Timer can become confused in this
manner and, as confusion loves company, how the Timer shares its confusion
with the next hapless caller that tries to submit a TimerTask. You might expect
the program to run for six seconds and exit, but what actually happens is that
it terminates after one second with an IllegalStateException whose message
text is “Timer already cancelled”. ScheduledThreadPoolExecutor deals properly
with ill-behaved tasks; there is little reason to use Timer in Java 5.0 or later.
If you need to build your own scheduling service, you may still be able to take
advantage of the library by using a DelayQueue, a BlockingQueue implementation
that provides the scheduling functionality of ScheduledThreadPoolExecutor. A
DelayQueue manages a collection of Delayed objects. A Delayed has a delay time
associated with it: DelayQueue lets you take an element only if its delay has
expired. Objects are returned from a DelayQueue ordered by the time associated
with their delay.

6.3 Finding exploitable parallelism


The Executor framework makes it easy to specify an execution policy, but in
order to use an Executor, you have to be able to describe your task as a Runn-
able. In most server applications, there is an obvious task boundary: a single
client request. But sometimes good task boundaries are not quite so obvious, as

6. Timer does have support for scheduling based on absolute, not relative time, so that tasks can be
sensitive to changes in the system clock; ScheduledThreadPoolExecutor supports only relative time.
124 Chapter 6. Task Execution

public class OutOfTime {


public static void main(String[] args) throws Exception {
Timer timer = new Timer();
timer.schedule(new ThrowTask(), 1);
SECONDS.sleep(1);
timer.schedule(new ThrowTask(), 1);
SECONDS.sleep(5);
}

static class ThrowTask extends TimerTask {


public void run() { throw new RuntimeException(); }
}
}

Listing 6.9. Class illustrating confusing Timer behavior.

in many desktop applications. There may also be exploitable parallelism within


a single client request in server applications, as is sometimes the case in database
servers. (For a further discussion of the competing design forces in choosing task
boundaries, see [CPJ 4.4.1.1].)
In this section we develop several versions of a component that admit varying
degrees of concurrency. Our sample component is the page-rendering portion of
a browser application, which takes a page of HTML and renders it into an image
buffer. To keep it simple, we assume that the HTML consists only of marked up
text interspersed with image elements with pre-specified dimensions and URLs.

6.3.1 Example: sequential page renderer


The simplest approach is to process the HTML document sequentially. As text
markup is encountered, render it into the image buffer; as image references are
encountered, fetch the image over the network and draw it into the image buffer
as well. This is easy to implement and requires touching each element of the
input only once (it doesn’t even require buffering the document), but is likely to
annoy the user, who may have to wait a long time before all the text is rendered.
A less annoying but still sequential approach involves rendering the text ele-
ments first, leaving rectangular placeholders for the images, and after completing
the initial pass on the document, going back and downloading the images and
drawing them into the associated placeholder. This approach is shown in Sin-
gleThreadRenderer in Listing 6.10.
Downloading an image mostly involves waiting for I/O to complete, and dur-
ing this time the CPU does little work. So the sequential approach may under-
utilize the CPU, and also makes the user wait longer than necessary to see the
finished page. We can achieve better utilization and responsiveness by breaking
the problem into independent tasks that can execute concurrently.
6.3. Finding exploitable parallelism 125

public class SingleThreadRenderer {


void renderPage(CharSequence source) {
renderText(source);
List<ImageData> imageData = new ArrayList<ImageData>();
for (ImageInfo imageInfo : scanForImageInfo(source))
imageData.add(imageInfo.downloadImage());
for (ImageData data : imageData)
renderImage(data);
}
}

Listing 6.10. Rendering page elements sequentially.

6.3.2 Result-bearing tasks: Callable and Future


The Executor framework uses Runnable as its basic task representation. Runn-
able is a fairly limiting abstraction; run cannot return a value or throw checked
exceptions, although it can have side effects such as writing to a log file or placing
a result in a shared data structure.
Many tasks are effectively deferred computations—executing a database
query, fetching a resource over the network, or computing a complicated func-
tion. For these types of tasks, Callable is a better abstraction: it expects that the
main entry point, call, will return a value and anticipates that it might throw
an exception.7 Executors includes several utility methods for wrapping other
types of tasks, including Runnable and java.security.PrivilegedAction, with
a Callable.
Runnable and Callable describe abstract computational tasks. Tasks are usu-
ally finite: they have a clear starting point and they eventually terminate. The
lifecycle of a task executed by an Executor has four phases: created, submitted,
started, and completed. Since tasks can take a long time to run, we also want to be
able to cancel a task. In the Executor framework, tasks that have been submitted
but not yet started can always be cancelled, and tasks that have started can some-
times be cancelled if they are responsive to interruption. Cancelling a task that
has already completed has no effect. (Cancellation is covered in greater detail in
Chapter 7.)
Future represents the lifecycle of a task and provides methods to test whether
the task has completed or been cancelled, retrieve its result, and cancel the task.
Callable and Future are shown in Listing 6.11. Implicit in the specification of
Future is that task lifecycle can only move forwards, not backwards—just like the
ExecutorService lifecycle. Once a task is completed, it stays in that state forever.
The behavior of get varies depending on the task state (not yet started, run-
ning, completed). It returns immediately or throws an Exception if the task
has already completed, but if not it blocks until the task completes. If the task
completes by throwing an exception, get rethrows it wrapped in an Execution-

7. To express a non-value-returning task with Callable, use Callable<Void>.


126 Chapter 6. Task Execution

public interface Callable<V> {


V call() throws Exception;
}

public interface Future<V> {


boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException,
CancellationException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException,
CancellationException, TimeoutException;
}

Listing 6.11. Callable and Future interfaces.

Exception; if it was cancelled, get throws CancellationException. If get throws


ExecutionException, the underlying exception can be retrieved with getCause.
There are several ways to create a Future to describe a task. The submit
methods in ExecutorService all return a Future, so that you can submit a Runn-
able or a Callable to an executor and get back a Future that can be used to
retrieve the result or cancel the task. You can also explicitly instantiate a Fut-
ureTask for a given Runnable or Callable. (Because FutureTask implements
Runnable, it can be submitted to an Executor for execution or executed directly
by calling its run method.)
As of Java 6, ExecutorService implementations can override newTaskFor in
AbstractExecutorService to control instantiation of the Future corresponding
to a submitted Callable or Runnable. The default implementation just creates a
new FutureTask, as shown in Listing 6.12.

protected <T> RunnableFuture<T> newTaskFor(Callable<T> task) {


return new FutureTask<T>(task);
}

Listing 6.12. Default implementation of newTaskFor in ThreadPoolExecutor.

Submitting a Runnable or Callable to an Executor constitutes a safe publica-


tion (see Section 3.5) of the Runnable or Callable from the submitting thread to
the thread that will eventually execute the task. Similarly, setting the result value
for a Future constitutes a safe publication of the result from the thread in which
it was computed to any thread that retrieves it via get.
6.3. Finding exploitable parallelism 127

6.3.3 Example: page renderer with Future


As a first step towards making the page renderer more concurrent, let’s divide it
into two tasks, one that renders the text and one that downloads all the images.
(Because one task is largely CPU-bound and the other is largely I/O-bound, this
approach may yield improvements even on single-CPU systems.)
Callable and Future can help us express the interaction between these coop-
erating tasks. In FutureRenderer in Listing 6.13, we create a Callable to down-
load all the images, and submit it to an ExecutorService. This returns a Future
describing the task’s execution; when the main task gets to the point where it
needs the images, it waits for the result by calling Future.get. If we’re lucky, the
results will already be ready by the time we ask; otherwise, at least we got a head
start on downloading the images.
The state-dependent nature of get means that the caller need not be aware
of the state of the task, and the safe publication properties of task submission
and result retrieval make this approach thread-safe. The exception handling code
surrounding Future.get deals with two possible problems: that the task encoun-
tered an Exception, or the thread calling get was interrupted before the results
were available. (See Sections 5.5.2 and 5.4.)
FutureRenderer allows the text to be rendered concurrently with download-
ing the image data. When all the images are downloaded, they are rendered onto
the page. This is an improvement in that the user sees a result quickly and it
exploits some parallelism, but we can do considerably better. There is no need for
users to wait for all the images to be downloaded; they would probably prefer to
see individual images drawn as they become available.

6.3.4 Limitations of parallelizing heterogeneous tasks


In the last example, we tried to execute two different types of tasks in parallel—
downloading the images and rendering the page. But obtaining significant per-
formance improvements by trying to parallelize sequential heterogeneous tasks
can be tricky.
Two people can divide the work of cleaning the dinner dishes fairly effectively:
one person washes while the other dries. However, assigning a different type of
task to each worker does not scale well; if several more people show up, it is not
obvious how they can help without getting in the way or significantly restructur-
ing the division of labor. Without finding finer-grained parallelism among similar
tasks, this approach will yield diminishing returns.
A further problem with dividing heterogeneous tasks among multiple workers
is that the tasks may have disparate sizes. If you divide tasks A and B between
two workers but A takes ten times as long as B, you’ve only speeded up the total
process by 9%. Finally, dividing a task among multiple workers always involves
some amount of coordination overhead; for the division to be worthwhile, this
overhead must be more than compensated by productivity improvements due to
parallelism.
FutureRenderer uses two tasks: one for rendering text and one for download-
ing the images. If rendering the text is much faster than downloading the images,
128 Chapter 6. Task Execution

public class FutureRenderer {


private final ExecutorService executor = ...;

void renderPage(CharSequence source) {


final List<ImageInfo> imageInfos = scanForImageInfo(source);
Callable<List<ImageData>> task =
new Callable<List<ImageData>>() {
public List<ImageData> call() {
List<ImageData> result
= new ArrayList<ImageData>();
for (ImageInfo imageInfo : imageInfos)
result.add(imageInfo.downloadImage());
return result;
}
};

Future<List<ImageData>> future = executor.submit(task);


renderText(source);

try {
List<ImageData> imageData = future.get();
for (ImageData data : imageData)
renderImage(data);
} catch (InterruptedException e) {
// Re-assert the thread’s interrupted status
Thread.currentThread().interrupt();
// We don’t need the result, so cancel the task too
future.cancel(true);
} catch (ExecutionException e) {
throw launderThrowable(e.getCause());
}
}
}

Listing 6.13. Waiting for image download with Future.


6.3. Finding exploitable parallelism 129

as is entirely possible, the resulting performance is not much different from the
sequential version, but the code is a lot more complicated. And the best we can do
with two threads is speed things up by a factor of two. Thus, trying to increase
concurrency by parallelizing heterogeneous activities can be a lot of work, and
there is a limit to how much additional concurrency you can get out of it. (See
Sections 11.4.2 and 11.4.3 for another example of the same phenomenon.)

The real performance payoff of dividing a program’s workload into tasks


comes when there are a large number of independent, homogeneous tasks
that can be processed concurrently.

6.3.5 CompletionService: Executor meets BlockingQueue


If you have a batch of computations to submit to an Executor and you want
to retrieve their results as they become available, you could retain the Future
associated with each task and repeatedly poll for completion by calling get with
a timeout of zero. This is possible, but tedious. Fortunately there is a better way:
a completion service.
CompletionService combines the functionality of an Executor and a Block-
ingQueue. You can submit Callable tasks to it for execution and use the queue-
like methods take and poll to retrieve completed results, packaged as Futures,
as they become available. ExecutorCompletionService implements Completion-
Service, delegating the computation to an Executor.
The implementation of ExecutorCompletionService is quite straightforward.
The constructor creates a BlockingQueue to hold the completed results. Future-
Task has a done method that is called when the computation completes. When a
task is submitted, it is wrapped with a QueueingFuture, a subclass of FutureTask
that overrides done to place the result on the BlockingQueue, as shown in Listing
6.14. The take and poll methods delegate to the BlockingQueue, blocking if
results are not yet available.

private class QueueingFuture<V> extends FutureTask<V> {


QueueingFuture(Callable<V> c) { super(c); }
QueueingFuture(Runnable t, V r) { super(t, r); }

protected void done() {


completionQueue.add(this);
}
}

Listing 6.14. QueueingFuture class used by ExecutorCompletionService.


130 Chapter 6. Task Execution

6.3.6 Example: page renderer with CompletionService


We can use a CompletionService to improve the performance of the page ren-
derer in two ways: shorter total runtime and improved responsiveness. We
can create a separate task for downloading each image and execute them in a
thread pool, turning the sequential download into a parallel one: this reduces the
amount of time to download all the images. And by fetching results from the
CompletionService and rendering each image as soon as it is available, we can
give the user a more dynamic and responsive user interface. This implementation
is shown in Renderer in Listing 6.15.

public class Renderer {


private final ExecutorService executor;

Renderer(ExecutorService executor) { this.executor = executor; }

void renderPage(CharSequence source) {


final List<ImageInfo> info = scanForImageInfo(source);
CompletionService<ImageData> completionService =
new ExecutorCompletionService<ImageData>(executor);
for (final ImageInfo imageInfo : info)
completionService.submit(new Callable<ImageData>() {
public ImageData call() {
return imageInfo.downloadImage();
}
});

renderText(source);

try {
for (int t = 0, n = info.size(); t < n; t++) {
Future<ImageData> f = completionService.take();
ImageData imageData = f.get();
renderImage(imageData);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
throw launderThrowable(e.getCause());
}
}
}

Listing 6.15. Using CompletionService to render page elements as they become


available.

Multiple ExecutorCompletionServices can share a single Executor, so it is


6.3. Finding exploitable parallelism 131

perfectly sensible to create an ExecutorCompletionService that is private to a


particular computation while sharing a common Executor. When used in this
way, a CompletionService acts as a handle for a batch of computations in much
the same way that a Future acts as a handle for a single computation. By remem-
bering how many tasks were submitted to the CompletionService and counting
how many completed results are retrieved, you can know when all the results for
a given batch have been retrieved, even if you use a shared Executor.

6.3.7 Placing time limits on tasks


Sometimes, if an activity does not complete within a certain amount of time, the
result is no longer needed and the activity can be abandoned. For example, a web
application may fetch its advertisements from an external ad server, but if the ad
is not available within two seconds, it instead displays a default advertisement so
that ad unavailability does not undermine the site’s responsiveness requirements.
Similarly, a portal site may fetch data in parallel from multiple data sources, but
may be willing to wait only a certain amount of time for data to be available
before rendering the page without it.
The primary challenge in executing tasks within a time budget is making
sure that you don’t wait longer than the time budget to get an answer or find
out that one is not forthcoming. The timed version of Future.get supports this
requirement: it returns as soon as the result is ready, but throws TimeoutExcep-
tion if the result is not ready within the timeout period.
A secondary problem when using timed tasks is to stop them when they run
out of time, so they do not waste computing resources by continuing to compute
a result that will not be used. This can be accomplished by having the task strictly
manage its own time budget and abort if it runs out of time, or by cancelling the
task if the timeout expires. Again, Future can help; if a timed get completes with
a TimeoutException, you can cancel the task through the Future. If the task is
written to be cancellable (see Chapter 7), it can be terminated early so as not to
consume excessive resources. This technique is used in Listings 6.13 and 6.16.
Listing 6.16 shows a typical application of a timed Future.get. It generates
a composite web page that contains the requested content plus an advertisement
fetched from an ad server. It submits the ad-fetching task to an executor, com-
putes the rest of the page content, and then waits for the ad until its time budget
runs out.8 If the get times out, it cancels9 the ad-fetching task and uses a default
advertisement instead.

6.3.8 Example: a travel reservations portal


The time-budgeting approach in the previous section can be easily generalized to
an arbitrary number of tasks. Consider a travel reservation portal: the user en-

8. The timeout passed to get is computed by subtracting the current time from the deadline; this may
in fact yield a negative number, but all the timed methods in java.util.concurrent treat negative
timeouts as zero, so no extra code is needed to deal with this case.
9. The true parameter to Future.cancel means that the task thread can be interrupted if the task is
currently running; see Chapter 7.
132 Chapter 6. Task Execution

Page renderPageWithAd() throws InterruptedException {


long endNanos = System.nanoTime() + TIME_BUDGET;
Future<Ad> f = exec.submit(new FetchAdTask());
// Render the page while waiting for the ad
Page page = renderPageBody();
Ad ad;
try {
// Only wait for the remaining time budget
long timeLeft = endNanos - System.nanoTime();
ad = f.get(timeLeft, NANOSECONDS);
} catch (ExecutionException e) {
ad = DEFAULT_AD;
} catch (TimeoutException e) {
ad = DEFAULT_AD;
f.cancel(true);
}
page.setAd(ad);
return page;
}

Listing 6.16. Fetching an advertisement with a time budget.

ters travel dates and requirements and the portal fetches and displays bids from
a number of airlines, hotels or car rental companies. Depending on the com-
pany, fetching a bid might involve invoking a web service, consulting a database,
performing an EDI transaction, or some other mechanism. Rather than have the
response time for the page be driven by the slowest response, it may be preferable
to present only the information available within a given time budget. For provi-
ders that do not respond in time, the page could either omit them completely or
display a placeholder such as “Did not hear from Air Java in time.”
Fetching a bid from one company is independent of fetching bids from an-
other, so fetching a single bid is a sensible task boundary that allows bid retrieval
to proceed concurrently. It would be easy enough to create n tasks, submit them
to a thread pool, retain the Futures, and use a timed get to fetch each result
sequentially via its Future, but there is an even easier way—invokeAll.
Listing 6.17 uses the timed version of invokeAll to submit multiple tasks to
an ExecutorService and retrieve the results. The invokeAll method takes a
collection of tasks and returns a collection of Futures. The two collections have
identical structures; invokeAll adds the Futures to the returned collection in the
order imposed by the task collection’s iterator, thus allowing the caller to associate
a Future with the Callable it represents. The timed version of invokeAll will
return when all the tasks have completed, the calling thread is interrupted, or
the timeout expires. Any tasks that are not complete when the timeout expires
are cancelled. On return from invokeAll, each task will have either completed
normally or been cancelled; the client code can call get or isCancelled to find
6.3. Finding exploitable parallelism 133

out which.

Summary
Structuring applications around the execution of tasks can simplify development
and facilitate concurrency. The Executor framework permits you to decouple
task submission from execution policy and supports a rich variety of execution
policies; whenever you find yourself creating threads to perform tasks, consider
using an Executor instead. To maximize the benefit of decomposing an applica-
tion into tasks, you must identify sensible task boundaries. In some applications,
the obvious task boundaries work well, whereas in others some analysis may be
required to uncover finer-grained exploitable parallelism.
134 Chapter 6. Task Execution

private class QuoteTask implements Callable<TravelQuote> {


private final TravelCompany company;
private final TravelInfo travelInfo;
...
public TravelQuote call() throws Exception {
return company.solicitQuote(travelInfo);
}
}

public List<TravelQuote> getRankedTravelQuotes(


TravelInfo travelInfo, Set<TravelCompany> companies,
Comparator<TravelQuote> ranking, long time, TimeUnit unit)
throws InterruptedException {
List<QuoteTask> tasks = new ArrayList<QuoteTask>();
for (TravelCompany company : companies)
tasks.add(new QuoteTask(company, travelInfo));

List<Future<TravelQuote>> futures =
exec.invokeAll(tasks, time, unit);

List<TravelQuote> quotes =
new ArrayList<TravelQuote>(tasks.size());
Iterator<QuoteTask> taskIter = tasks.iterator();
for (Future<TravelQuote> f : futures) {
QuoteTask task = taskIter.next();
try {
quotes.add(f.get());
} catch (ExecutionException e) {
quotes.add(task.getFailureQuote(e.getCause()));
} catch (CancellationException e) {
quotes.add(task.getTimeoutQuote(e));
}
}

Collections.sort(quotes, ranking);
return quotes;
}

Listing 6.17. Requesting travel quotes under a time budget.


Google
Bookmarks Delicious Digg Facebook StumbleUpon Reddit Twitter

Java_Rock_Star_CH_Openers.indd 5 6/18/09 1:49:52 PM


Eric J. Bruno
Greg Bollella, Ph.D.


Real-Time Java Programming

The Definitive Guide to Java RTS for Developers and Architects


• For Java developers and architects moving to real-time, and real-time developers AVAILABLE
moving to Java
• BOOK: 9780137142989
• Walks through start-to-finish case study applications, identifying their constraints
• SAFARI ONLINE
and discussing the APIs and design patterns used to address them
• EBOOK: 0137153627
• By the former leader of the real-time Java standards process and one of Wall Street’s
• KINDLE: 0137042582
top real-time developers

Sun Microsystems’ Java Real-Time System (Java RTS) is proving itself in numerous, About the Authors
wide-ranging environments, including finance, control systems, manufacturing, and
defense. Java RTS and the RTSJ standard (JSR-001) eliminate the need for complicated, Eric J. Bruno, systems engineer at
specialized, real-time languages and operating environments, saving money by leverag- Sun Microsystems, specializes in Java
ing Java’s exceptional productivity and familiarity. RTS in the financial community. He is
contributing editor for Dr. Dobb’s Jour-
In Real-Time Java™ Programming, two of Sun’s top real-time programming nal, and writes its online Java blog.
experts present the deep knowledge and realistic code examples that developers need Prior to Sun, Eric worked at Reuters
to succeed with Java RTS and its APIs. As they do so, the authors also illuminate the where he developed real-time trading
foundations of real-time programming in any RTSJ-compatible environment. systems, order-entry and routing
systems, as well as real-time news and
Key topics include: quotes feeds, in both Java and C++.

• Real-time principles and concepts, and the unique requirements of real-time Greg Bollella, Ph.D., distinguished
application design and development engineer at Sun Microsystems, leads
• How Java has been adapted to real-time environments R&D for real-time Java. He was specifi
• A complete chapter on garbage collection concepts and Java SE collectors cation lead for JSR-001, the Real-Time
• Using the Java RTS APIs to solve actual real-time system problems as efficiently Specification for Java (RTSJ), and led
as possible the Real-Time for Java Expert Group
• Utilizing today’s leading Java RTS development and debugging tools under the Java Community Process.
• Understanding real-time garbage collection, threads, scheduling, and dispatching He has written multiple books, articles,
• Programming new RTSJ memory models and professional papers about real-
• Dealing with asynchronous event handling and asynchronous transfer of control time computing. He has a Ph.D. in
computer science from the University
of North Carolina at Chapel Hill, where
he wrote a dissertation on real-time
scheduling theory and real-time
systems implementation.

informit.com/ph

Java_Rock_Star_CH_Openers.indd 6 6/18/09 1:49:53 PM


1
Real-Time for the
Rest of Us
“Let him who would enjoy a good future waste none of his present.”
—Roger Babson

THERE are many misunderstandings about what real-time is, even amongst sea-
soned enterprise Java developers. Some confuse it with high-performance, or fast,
computing; others think of dynamic applications such as instant messaging. Neither
one is necessarily an example of a real-time system. Therefore real-time does not
always equal “real fast,” although good performance is often desirable and achievable.
In fact, real-time is often orthogonal with high-throughput systems; there’s a trade-off
in throughput in many cases. The best way to avoid all of this confusion is to think of it
this way: application performance and throughput requirements can be solved with
faster, or additional, hardware; real-time requirements, in general, cannot.
This chapter will define real-time computing, and will explain why throwing hardware
at a real-time requirement will almost never do any good. We’ll discuss the qualities of
a real-time system, define key terms used in the discipline, and examine tools, lan-
guages, and environments available to real-time developers outside of the Java world.
By the end of this chapter, you’ll have a good real-time foundation to build upon.

Qualities of Real-Time Systems


The goal of a real-time system is to respond to real-world events before a measur-
able deadline, or within a bounded time frame. However, a real-time system is
also about precision. The measured speed of a system’s response to an event is

Bruno_Chapter1.indd 3 5/15/09 2:13:16 AM


4 CHAPTER 1 REAL-TIME FOR THE REST OF US

important, but what’s also important is the system’s ability to respond at precisely
the right moment in time. Access to a high-resolution timer to perform actions on
precise time periods is often a requirement. These two qualities together best
define a real-time application’s acceptable behavior: the ability to respond to an
event before a deadline, and accurately perform periodic processing, regardless of
overall system load. Before we go any further, it’s important to examine the term
deadline a little more closely, as well as some other terms often used in the context
of real-time systems.
The term deadline can have one of two meanings. First, it can be a deadline rela-
tive to an event, such as a notification or message in some form. In this case, the
system must respond to that event within a certain amount of time of receiving
that event, or from when that event originally occurred. One example of a relative
deadline is an elevator as it passes over a sensor indicating that it’s almost at the
floor it’s meant to stop at. The real-time software within the elevator must respond
to that event within milliseconds of passing the sensor, or it won’t be able to stop
at the intended floor. The occupants of an elevator that skips stops are certain to
consider this an error.

Relative Deadline (Di ): the amount of time after a request is made that the sys-
tem needs to respond.
Absolute Deadline (di ): the precise point in time that a task must be completed,
regardless of task start time, or request arrival.

Often, with an absolute deadline, a real-time system checks for a particular sys-
tem state on a regular interval. Some examples of this are an aircraft flight control
system, or a nuclear power plant’s core temperature monitoring system. In both of
these cases, critical data is continuously polled, such as altitude, or core tempera-
ture. Failing to monitor these values at precise points in time can cause these
systems to go into a bad state with potentially catastrophic results.
Regardless of the type of deadline, relative or absolute, time is still a main compo-
nent in proper system behavior. It’s not enough that an elevator’s software knows
and responds to a floor sensor; it must do so within a deadline in order to behave
correctly. Also, a flight control system must be able to move an aircraft’s control
surfaces at the precise time, in reaction to the most recent and accurate set of data,
in order to fly the aircraft correctly (without crashing!).
For example, let’s say we have a system requirement to send a response to a
request within one millisecond. If the system responds within 500 microseconds
every time, you may think the requirement has been met. However, if the request
is delayed, outside the system under measurement, the response will not have

Bruno_Chapter1.indd 4 5/15/09 2:13:17 AM


QUALITIES OF REAL-TIME SYSTEMS 5

been sent at the right moment in time (even if it’s sent within one millisecond).
Remember, we’re talking about “real” time here; the one-millisecond require-
ment applies to when the originating system sent the original request.
Figure 1-1 illustrates the problem. Here you see that the system in question has
responded to the request within one millisecond, but it was at the wrong time
because the request was delayed in delivery. A real-time system must adhere to
the end-to-end deadline.
In a real-time system, the time delay from when a real-world event occurs (such as
an object passing over a sensor, or the arrival of a stock market data-feed tick) to
the time some code finishes processing that event should be reasonably bounded.
The ability to meet this deadline must be predictable and guaranteed, all the time,
in order to provide the determinism needed for a real-time system.

What Is “Bounded”?
When we use the term bounded in relation to a bounded amount of time, what we
really imply is a reasonable amount of time for the system to respond. In other
words, saying that the elevator responds to sensor events within a ten-year bounded
timeframe is unreasonable. It must do so according to a time requirement that
allows it to function properly. Therefore, when we use the term bounded, it’s
relative to the proper operation of the time-critical event we’re describing.

When discussing real-time systems, the basic element of execution is often


referred to as a job, or task. (For a more accurate definition of jobs and tasks in
real-time systems, see the note on Jobs and Tasks in Real-Time Systems). There
can be one or more tasks in a given system, and therefore tasks can either be

request latency
sent
Component 1
response
sent
Component 2

start .5 1
msec msec

Missed
deadline

Figure 1-1 The response time was good, but the deadline was missed. This is not a
real-time system.

Bruno_Chapter1.indd 5 5/15/09 2:13:17 AM


6 CHAPTER 1 REAL-TIME FOR THE REST OF US

running or waiting. On a uniprocessor machine, only one task can be running at a


single point in time, as opposed to multiprocessor machines that can execute more
than one task at a time.

Note: Jobs and Tasks in Real-Time Systems At this point in the discussion, it’s
fair to accurately define the terms job and task as used in discussions of real-time
scheduling theory. Formally speaking, a job is any unit of work that can be scheduled
and processed, while a task is a group of related jobs that work together to achieve
some function. In this classic definition, a task contains related jobs, where those jobs
have real-time constraints.
However, to keep the discussions light and simple in this book we will not distinguish
between tasks and jobs; a unit of schedulable work will simply be referred to as a task.
Therefore, in this book, a task represents a thread of execution and is synonymous
with an OS thread.

Regardless, discussions often revolve around the arrival of a system event, or the
start of task execution, which can sometimes be one and the same. To clarify, we
say that a task can be in one of the three main states:

Eligible-for-Execution: the task is eligible (ready) to execute.


Executing: the task is currently executing (running) on a processor.
Blocked: the task is neither executing, nor eligible to begin executing. It’s
blocked for some reason, and this reason is usually stated as part of the state;
i.e., blocked-for-IO, blocked-for-release-event, and so on.

With these task states defined, we can begin to discuss how tasks are scheduled in
a real-time system. First, the following definitions must be stated:

Release Time (ri ): sometimes called arrival time, or request time, this is the
time that a task becomes ready to execute.
Start Time (si ): the time that a task begins executing. As stated above, these
concepts may be combined for simplification in many discussions. For exam-
ple, a task may be started because of a request, or it may be started as part of a
predefined schedule. This book shall attempt to separate these concepts when
necessary to avoid confusion.
Finish Time ( fi ): the time when a task is complete.

Bruno_Chapter1.indd 6 5/15/09 2:13:17 AM


PREDICTABILITY AND DETERMINISM 7

Task Completion Time (Ci = fi − ri ): the amount of time a particular task takes
to complete its processing by subtracting the task’s arrival time from its finish
time. This is also referred to as the cost of task execution.
Lateness (Li ): the difference between the task finish time and its deadline; note
that this value is negative if a task completes before its deadline, zero if it com-
pletes at its deadline, and positive if it completes after its deadline.

These terms and their associated abbreviations will be used throughout the book.
To further clarify them, and to gain a better understanding of real-time systems,
let’s explore the factors that affect a system’s ability to meet its deadlines.

Predictability and Determinism


Other important qualities of a real-time system are that of predictability and deter-
minism. A real-time system must behave in a way that can be predicted mathemat-
ically. This refers to the system’s deadline in terms of relative and absolute time.
For instance, it must be mathematically predictable to determine if the amount of
work to be done can be completed before a given deadline. Factors that go into
this calculation are system workload, the number of CPUs (or CPU cores) avail-
able for processing, running threads in the real-time system, process and thread
priorities, and the operating system scheduling algorithm.
Determinism represents the ability to ensure the execution of an application
without concern that outside factors will upset the execution in unpredictable
ways. In other words, the application will behave as intended in terms of func-
tionality, performance, and response time, all of the time without question. In
many respects, determinism and predictability are related, in that one results in
the other. However, the important distinction is that a deterministic system puts
the control of execution behavior in the hands of the application developer. Pre-
dictability is then the result of proper programming practice on a system that
enables such behavior. This book will explore the statement “proper program-
ming practice” in relation to real-time applications written in Java because using
a real-time language or operating system is never enough—discipline is also
required.
Another aspect of deterministic application behavior is that it’s fixed, more or
less. This means that unforeseen events, such as garbage collection in Java, must
never upset a real-time application’s ability to meet its deadlines, and hence
become less predictable. A real-time system such as an anti-lock brake system, or

Bruno_Chapter1.indd 7 5/15/09 2:13:17 AM


8 CHAPTER 1 REAL-TIME FOR THE REST OF US

an airplane’s flight-control system, must always be 100% deterministic and


predictable or human lives may be at stake.
Many practical discussions of real-time systems and their requirements involve
the terms latency and jitter. Let’s examine these now, and form precise definitions
that we’ll use in our discussion going forward.

Identifying Latency
Much of the discussion so far has been about responding to an event before a
deadline. This is certainly a requirement of a real-time system. Latency is a
measure of the time between a particular event and a system’s response to that
event, and it’s quite often a focus for real-time developers. Because of this,
latency is often a key measurement in any real-time system. In particular, the
usual focus is to minimize system latency. However, in a real-time system
the true goal is simply to normalize latency, not minimize it. In other words, the
goal is to make latency a known, reasonably small, and consistent quantity that
can then be predicted. Whether the latency in question is measured in seconds,
or microseconds, the fact that it can be predicted is what truly matters to real-
time developers. Nonetheless, more often than not, real-time systems also
include the requirement that latency be minimized and bounded, often in the
sub-millisecond range.
To meet a system’s real-time requirements, all sources of latency must be
identified and measured. To do this, you need the support of your host system’s
operating system, its environment, network relationship, and programming
language.

Identifying Jitter
The definition of jitter includes the detection of irregular variations, or unsteadi-
ness, in some measured quantity. For example, in an electronic device, jitter
often refers to a fluctuation in an electrical signal. In a real-time system, jitter is
the fluctuation in latency for similar event processing. Simply measuring the
latency of message processing for one event, or averaging it over many events, is
not enough. For instance, if the average latency from request to response for a
certain web server is 250 milliseconds, we have no insight into jitter. If we look
at all of the numbers that go into the average (all of the individual request/
response round-trip times) we can begin to examine it. Instead, as a real-time
developer, you must look at the distribution and standard deviation of the
responses over time.

Bruno_Chapter1.indd 8 5/15/09 2:13:17 AM


PREDICTABILITY AND DETERMINISM 9

Other Causes of Jitter


Jitter can also be caused by the scheduling algorithm in your real-time system. For
instance, in a system with many real-time periodic tasks, a particular task can finish
anywhere within its time period. If it sometimes finishes early in its period (well
before the deadline), but other times it finishes just before the period end, it has
jitter. In some systems, there are control algorithms that cannot tolerate this.
For example, say we have a task with a 100-millisecond period, where the
execution cost is 10 milliseconds, and the worst-case latency is always less than
1 millisecond. In a complex system, this task can finish anywhere from the period
boundary + 10 milliseconds processing time + 1 millisecond latency, to the period
boundary + 100 milliseconds (start of next period). One solution to this problem,
the one proposed by the Real-Time Specification for Java (RTSJ) in particular, is to
set the deadline to 12 milliseconds.

The chart in Figure 1-2 shows a sampling of latency data for a web server’s
request/response round-trip time. You can see that although the average of 250
milliseconds seems pleasing, a look at the individual numbers shows that some of
the responses were delivered with up to one-second latency. These “large” latency

System Throughput
3500

3000
Round-trip processing time (microseconds)

2500

2000

1500

1000

500

0
1 64 127 190 253 316 379 442 505 568 631 694 757 820 883 946
Message Number

Figure 1-2 The average response time measurement of a transaction can cover up
latency outliers.

Bruno_Chapter1.indd 9 5/15/09 2:13:18 AM


10 CHAPTER 1 REAL-TIME FOR THE REST OF US

responses stand out above most of the others, and are hence labeled outliers, since
they fall outside of the normal, or even acceptable, response time range.
However, if the system being measured is simply a web application without real-
time requirements, this chart should not be alarming; the outliers simply aren’t
important, as the average is acceptable. However, if the system were truly a real-
time system, these outliers could represent disaster. In a real-time system, every
response must be sent within a bounded amount of latency.

Hard and Soft Real-Time


In the real-time problem domain, discussions often involve the terms hard real-
time and soft real-time. Contrary to what many people assume, these terms have
nothing to do with the size of the deadline, or the consequence of missing that
deadline. It’s a common misconception that a hard real-time system has a smaller,
or tighter, deadline in terms of overall time than a soft real-time system. Instead, a
hard real-time system is one that cannot miss a single deadline or the system will
go into an abnormal state. In other words, the correctness of the system depends
not only on the responses it generates, but the time frame in which each and every
response is delivered. A soft real-time system is one that may have a similar dead-
line in terms of time, but it instead has the tolerance to miss a deadline occasion-
ally without generating an error condition.
For example, let’s compare a hypothetical video player software application to an
automated foreign exchange trading application. Both systems have real-time
qualities:
• The video player must retrieve and display video frames continuously, with
each frame being updated by a deadline of, say, one millisecond.
• A foreign exchange trade must be settled (moneys transferred between
accounts) within exactly two days of the trade execution.
The video player has a far more constraining deadline at one millisecond com-
pared to the two-day deadline of the trading system. However, according to our
definition, the trading system qualifies as a hard real-time system, and the video
player as a soft real-time system, since a missed settlement trade puts the entire
trade, and trading system, into a bad state—the trade needs to be rolled back,
money is lost, and a trading relationship strained. For the video player, an occa-
sional missed deadline results in some dropped frames and a slight loss of video
quality, but the overall system is still valid. However, this is still real-time since
the system must not miss too many deadlines (and drop too many frames) or it,
too, will be considered an error.

Bruno_Chapter1.indd 10 5/15/09 2:13:18 AM


PREDICTABILITY AND DETERMINISM 11

Additionally, the severity of the consequence of missing a deadline has nothing to


do with the definition of hard versus soft. Looking closer at the video player soft-
ware in the previous example, the requirement to match audio to the corresponding
video stream is also a real-time requirement. In this case, many people don’t con-
sider the video player to be as critical as an anti-lock brake system, or a missile-
tracking system. However, the requirement to align audio with its corresponding
video is a hard real-time constraint because not doing so is considered an error con-
dition. This shows that whereas the consequence of a misaligned video/audio stream
is minimal, it’s still a hard real-time constraint since the result is an error condition.
Therefore, to summarize hard and soft real-time constraints, a hard real-time sys-
tem goes into a bad state when a single deadline is missed, whereas a soft real-
time system has a more flexible deadline, and can tolerate occasional misses. In
reality, it’s best to avoid these terms and their distinction and instead focus on
whether a system has a real-time requirement at all. If there truly is a deadline the
system must respond within, then the system qualifies as real-time, and every
effort should be made to ensure the deadline is met each time.

Isochronal Real-Time
In some cases, the requirement to respond to an event before a deadline is not
enough; it must not be sent too early either. In many control systems, responses
must be sent within a window of time after the request, and before the absolute
deadline (see Figure 1-3). Such a system has an isochronal real-time requirement.
Although clearly distinct from a hard real-time task that needs to complete any
time before its deadline, in most cases isochronal real-time tasks are simply clas-
sified as hard real-time with an additional timing constraint. This certainly makes
it easier to describe the tasks in a system design. However, this added constraint
does make a difference to the real-time task scheduler, which is something we’ll
explore later in this chapter.
Valid
response
window
Time
Task
ine
est

t
lies

adl
qu

Ear
Re

De

Figure 1-3 Isochronal real-time: the deadline must be met, but a response must not be
sent too early, either.

Bruno_Chapter1.indd 11 5/15/09 2:13:18 AM


12 CHAPTER 1 REAL-TIME FOR THE REST OF US

Real-Time Versus Real Fast


Application or system performance is a relative measurement. When a system is
said to be fast or slow, it’s usually in comparison to something else. Perhaps it’s an
older system, a user expectation, or a comparison to an analogous real-world sys-
tem. In general, performance is more of a relative measurement than a precise
mathematical statement. As discussed earlier in this chapter, real-time does not
necessarily equal real fast.
Instead, whereas the objective of fast computing is to minimize the average
response time of a given set of tasks, the objective of real-time computing is to
meet the individual time-critical requirement of each task. Consider this anec-
dote: there once was a man who drowned in a river with an average depth of
6 inches [Buttazzo05]. Of course, the key to that sentence is the use of the average
depth, which implies the river is deeper at some points. A real-time system is
characterized by its deadline, which is the maximum time within which it must
complete its execution, not the average.
However, the goals of most real-time systems are to meet critical deadlines and to
perform optimally and efficiently. For example, a system with sub-millisecond
deadlines will most likely require high-performance computer hardware and soft-
ware. For this reason, real-time systems programming is often associated with
high-performance computing (HPC). However, it’s important to remember that
high-performance does not imply real-time, and vice versa.

Real-Time Versus Throughput


Another area of system performance that is often confused with real-time is that
of system throughput. Throughput is often used to describe the number of
requests, events, or other operations, that a software system can process in any
given time frame. You often hear of software positively characterized with terms
like “messages-per-second,” or “requests-per-second.” A system with high
throughput can give its operators a false sense of security when used in a real-
time context.
This is because a system with high throughput is not necessarily a real-time sys-
tem, although it is often misunderstood to be. For instance, a system that supports
thousands of requests per second may have some responses with up to a second of
latency. Even though a majority of the requests may be handled with low latency,
the existence of some messages with large latency represents outliers (those out-
side the normal response time). In other words, with this example, most request-
ors received their responses well within the one-second window. However, there

Bruno_Chapter1.indd 12 5/15/09 2:13:19 AM


PREDICTABILITY AND DETERMINISM 13

were some that waited the full second for their response. Because the degree of,
and the amount of, these outliers are unpredictable, high-throughput systems are
not necessarily real-time systems.
Typically, real-time systems exhibit lower average throughput than non-real-time
systems. This engineering trade-off is well known and accepted in the real-time
community. This is due to many factors that include trade-offs as to how tasks are
scheduled and how resources are allocated. We’ll explore these factors in relation
to Java RTS throughout this book.

Task Completion Value


In a modern computing system, the basic element of execution is called a thread,
or a task. A process is defined as an application launched by the user (either explic-
itly through a command, or implicitly by logging in) that contains one or more
threads of execution. Regardless of how each task begins executing, the basic unit
of execution is a thread. To simplify things going forward, the thread will be the
focus of the discussion.
The value, or usefulness, that a task has to any running system is usually depen-
dent upon when it gets its work done, not just that the work is done properly. Even
non-real-time systems have this quality. For example, the chart in Figure 1-4
shows that the value of tasks in a non-real-time system usually increases as more
of them are completed over time. This is evidence of the throughput quality of
non-real-time systems, as explained in the previous section.
For a soft real-time system, the value of task completion rapidly decreases once
the task’s deadline passes. Although the correct answer may have been generated,
it gets more and more useless as time passes (see Figure 1-5).
Contrast this to a hard real-time system, where the task has zero value after the
deadline (see Figure 1-6).

me
a l-ti letion
e
n-r mp
Value

No k co
ta s

Time

Figure 1-4 In a non-real-time system, the perceived value of task completion is directly
proportional to the total number completed over time.

Bruno_Chapter1.indd 13 5/15/09 2:13:19 AM


14 CHAPTER 1 REAL-TIME FOR THE REST OF US

Value

Soft real-time
task completion

Time

ine
adl
De

Figure 1-5 In a soft real-time system, the value of task completion, after the deadline,
decays over time.
Value

Hard real-time
task completion

Time
ine
adl
De

Figure 1-6 The value of task completion in a hard real-time system is zero the moment
the deadline passes.

Isochronal real-time
task completion
Value

Time
ine
adl
De

Figure 1-7 The value of task completion in a firm, isochronal, real-time system is zero
if it completes early, or late.

The discussion so far assumes that task completion anytime before the deadline is
acceptable. In some cases, as with firm, or isochronal, real-time systems, the task
must complete before the deadline, but no earlier than a predefined value. In this
case, the value of task completion before and after the deadline is, or quickly goes
to, zero (see Figure 1-7).

Bruno_Chapter1.indd 14 5/15/09 2:13:19 AM


REAL-TIME COMPUTING 15

Of course, these graphs are only general visual representations of task completion
value in non-real-time and real-time systems; actual value is derived on a case-by-
case basis. Later in this chapter, we’ll examine this in more detail as task cost
functions are used to calculate efficient real-time scheduling algorithms.

Real-Time Computing
Now that you have an understanding of what real-time is and what it means, it’s time
to expand on it. Real-time computing is the study and practice of building applica-
tions with real-world time-critical constraints. Real-time systems must respond to
external, often physical, real-world events at a certain time, or by a deadline. A real-
time system often includes both the hardware and the software in its entirety. Tradi-
tionally, real-time systems were purpose-built systems implemented for specific
use; it’s only recently that the real-time community has focused on general-purpose
computing systems (both hardware and/or software) to solve real-time problems.
Today, the need for specialized, dedicated, hardware for real-time systems has mostly
disappeared. For instance, modern chipsets include programmable interrupt control-
lers with latency resolution small enough for demanding real-time applications. As a
result, support for real-time requirements has moved to software; i.e., specialized
schedulers and resource controllers. Algorithms that were once etched into special
circuitry are now implemented in software on general-purpose computers.
This is not to say that hardware support isn’t needed in a real-time system. For exam-
ple, many real-time systems will likely require access to a programmable interrupt
controller for low-latency interrupts and scheduling, a high-resolution clock for pre-
cise timing, direct physical memory access, or a high-speed memory cache. Most
modern computer hardware, including servers, workstations, and even desktops and
laptops, support these requirements. The bottom line is whether the operating sys-
tem software running on this hardware supports access to these hardware facilities.
The operating system may, in fact, support real-time tasks directly through its
scheduling implementation, or may at least allow alternative scheduling algo-
rithms be put in place. However, many general-purpose operating systems sched-
ule tasks to achieve different goals than a real-time system. Other factors, such as
overall system throughput, foreground application performance, and GUI refresh
rates, may be favored over an individual task’s latency requirements. In fact, in a
general-purpose system, there may be no way to accurately specify or measure an
application’s latency requirements and actual results.
However, it is still possible to achieve real-time behavior, and meet real-time
tasks’ deadlines, on general-purpose operating systems. In fact, this is one of the

Bruno_Chapter1.indd 15 5/15/09 2:13:20 AM


16 CHAPTER 1 REAL-TIME FOR THE REST OF US

charter goals that Java RTS, and the RTSJ, set out to solve: real-time behavior in
Java on general-purpose hardware and real-time operating systems. In reality,
only a subset of general-purpose systems can be supported.
The remainder of this chapter provides an overview of the theory and mechanics
involved in scheduling tasks in a real-time system. To be clear, real-time scheduling
theory requires a great deal of math to describe and understand thoroughly. There is
good reason for this: when a system has requirements to meet every deadline for
actions that may have dire consequences if missed, you need to make assurances with
the utmost precision. Characterizing and guaranteeing system behavior with mathe-
matics is the only way to do it. However, we’ll attempt to discuss the subject without
overburdening you with deep mathematical concepts. Instead, analogies, descriptions,
and visuals will be used to bring the concepts down to earth, at a level where the aver-
age programmer should be comfortable. For those who are interested in the deeper
math and science of the subject, references to further reading material are provided.

The Highway Analogy


One simple way to describe the dynamics of scheduling tasks in a real-time sys-
tem is to use a highway analogy. When driving a car, we’ve all experienced the
impact of high volume; namely, the unpredictable amount of time spent waiting in
traffic instead of making progress towards a destination. This situation is strik-
ingly similar to scheduling tasks in a real-time system, or any system, for that
matter. In the case of automobile traffic, the items being scheduled are cars, and
the resource that they’re all sharing is road space. Comparatively, a computer sys-
tem schedules tasks, and the resource they share is CPU time. (Of course, they
also share memory, IO, disk access, and so on, but let’s keep it simple for now.)
In the highway analogy, the lanes represent overall computer resources, or time
available to process tasks. More capable computers can be loosely described as
having more lanes available, while less capable systems have fewer. A car is
equivalent to a task that has been released (eligible for execution). Looking at
Figure 1-8, you can see tasks “traveling” down individual lanes, making forward

Active tasks over time, t

busy very busy not busy

t t 1 1... t 1n

Figure 1-8 As with cars on a highway, when there are more tasks executing, the system
slows down, and execution times become unpredictable.

Bruno_Chapter1.indd 16 5/15/09 2:13:20 AM


REAL-TIME COMPUTING 17

progress over time. At moments when more tasks share the highway, the entire
system is considered to be busy, and usually all tasks will execute slower. This is
similar to the effects that high volumes of cars have on individual car speeds; they
each slow down as they share the highway. Since, in this scenario, all tasks share
the resources (the highway) equally, they are all impacted in a similar, but
unpredictable, way. It’s impossible to deterministically know when an individual
task will be able to complete.
In the real world, engineers designing road systems have come up with a solution
to this problem: a dedicated lane.

The Highway Analogy—Adding a Priority Lane


Figure 1-9 proposes a specialized solution to this problem: a dedicated high-
priority lane (sometimes called a carpool, or HOV lane, on a real highway). We
refer to it as specialized because it doesn’t help all tasks in the system (or all cars
on the highway), only those that meet the requirements to enter the high-priority
lane. Those tasks (or cars) receive precedence over all others, and move at a more
predictable pace. Similarly, in a real-time system, dedicating system resources to
high-priority tasks ensures that those tasks gain predictability, are less prone to
traffic delay, and therefore complete more or less on time. Only the normal
(lower-priority) tasks feel the effects of high system volume.
This analogy goes a long way towards describing, and modeling, the dynamics of
a real-time system. For instance:
• Tasks in the high-priority lane gain execution precedence over other tasks.
• Tasks in the high-priority lane receive a dedicated amount of system
resources to ensure they complete on time.
• When the system is busy, only normal tasks feel the impact; tasks in the
high-priority lane are almost completely unaffected.

Active tasks over time, t

High-priority lane

busy not busy

very busy
t t 1 1... t 1n

Figure 1-9 Introducing a high-priority lane to a highway ensures that the cars in that
lane are less susceptible to traffic, and therefore travel more predictably towards their
destinations.

Bruno_Chapter1.indd 17 5/15/09 2:13:21 AM


18 CHAPTER 1 REAL-TIME FOR THE REST OF US

• Overall, the system loses throughput, as fewer lanes are available to execute
tasks.
• Tasks only enter the high-priority lane at certain checkpoints.
• Some system overhead is required at the checkpoints. Just as cars need to
cautiously (and slowly) enter and exit a carpool lane, tasks are slightly
impacted.
• Tasks may be denied access to the high-priority lane if their entry would
adversely affect the other tasks already running.
Additionally, metering lights are used at the on-ramps to many highways. These
lights control the flow of additional cars (analogy: new tasks) onto the highway to
ensure the cars already on the highway are impacted as little as possible. These
lights are analogous to the admission control algorithm of the scheduler in real-
time system.
Most importantly, this analogy shows that there’s no magic involved in supporting
a real-time system; it, too, has its limits. For instance, there’s a limit to the number
of high-priority tasks that can execute and meet their deadlines without causing
all tasks to miss their deadlines. Also, because of the need to dedicate resources to
real-time tasks, the added checkpoints for acceptance of real-time tasks, the need
to more tightly control access to shared resources, and the need to perform addi-
tional task monitoring; the system as a whole will assuredly lose some perfor-
mance and/or throughput. However, in a real-time system, predictability trumps
throughput, which can be recovered by other, less-complicated, means.
As we explore the details of common scheduling algorithms used in actual real-
time systems, you will also see that simply “adding more lanes” doesn’t always
resolve the problem effectively. There are practical limits to any solution. In fact,
in some cases that we’ll explore, adding processors to a computer can cause previ-
ously feasible schedules to become infeasible. Task scheduling involves many
system dynamics, where the varying combination of tasks and available resources
at different points in time represents a difficult problem to solve deterministically.
However, it can be done. Let’s begin to explore some of the common algorithms
used, and the constraints they deal with.

Real-Time Scheduling
A task by itself represents a useless body of instructions. For a task to be useful
and meaningful, it must be processed, and it therefore must have scheduled exe-
cution time on a processor. The act of scheduling processor time to a task, or

Bruno_Chapter1.indd 18 5/15/09 2:13:21 AM


REAL-TIME SCHEDULING 19

thread, and assigning it a free processor is often called dispatching. Real-time


schedulers can schedule individual tasks for execution either offline (prior to the
system entering its running state) or online (while the system is in an active, run-
ning state). Regardless of when it occurs, all scheduling work is done according to
a predefined algorithm, or set of rules.

Scheduling Constraints
Many factors, or constraints, are taken into account when scheduling real-time
tasks. Because each application—and hence each task—is different, these con-
straints may vary from system to system. However, they all generally fall into a
subset of constraints that need to be considered. The first constraint is the amount
of available resources; whether they’re tasks in a computer or construction work-
ers on a job, having what you need to complete a task is important. The second
constraint is task precedence; to avoid chaos, and to ensure proper system behav-
ior, certain tasks may need to be executed before others. The third constraint is
timing; each task has its own deadline, some tasks execute longer than others,
some may execute on a steady period, and others may vary between release times.
Each constraint contains many of its own factors that need to be considered fur-
ther when scheduling tasks. Let’s examine these constraints in more detail now,
and how they may affect task scheduling.

Resources
Because we speak in terms of processors, tasks, and execution times, most people
think of only the CPU as the main resource to be scheduled. This isn’t always the
case. For example, recalling the highway analogy above, cars represented tasks,
and the road represented the processor. More realistically, in a real-time network
packet switching system, tasks represent data packets, and the processor repre-
sents an available communication line. Similarly, in a real-time file system, a task
is a file, and the processor is an individual disk platter/head combination. How-
ever, regardless of the actual physical work being done (sending a packet, writing
a file, or executing a thread), we will refer to all of them as simply a task. Further,
regardless of the actual component doing the work (a network card/communica-
tion link, a disk controller, or a CPU), we will refer to all of them as simply a
processor.
It’s easy to see how the availability of critical system resources, such as the pro-
cessor, is important to a scheduling algorithm. After all, to execute a thread, there
must be a CPU available to execute it. However, it goes beyond just the processor;
other resources, such as shared objects that require synchronization across tasks,

Bruno_Chapter1.indd 19 5/15/09 2:13:21 AM


20 CHAPTER 1 REAL-TIME FOR THE REST OF US

are to be considered. This may be something as abstract as a shared object in


memory, or something more concrete such as a shared region of memory, or the
system bus. Regardless, there is often a need to lock shared resources to avoid
errors due to concurrent access. This effectively limits a resource to being updated
atomically, by one task at a time. Since resource locking synchronizes access to a
shared resource, one task may become blocked when attempting to access a
resourced that is currently locked by another task.
In a real-time system, it’s important to ensure that high-priority, hard real-time
tasks continue to make progress towards completion. Resource locking is
commonly a problem since priority inversion can cause tasks to execute out of
order. In many general-purpose operating systems, resource locking can lead to
priority inversion, resulting in unbounded latency for critical tasks, and missed
deadlines in a hard real-time system. For instance, in Figure 1-10, we see three
tasks, T1, T2, and T3, each with decreasing priority, respectively.
In this scenario, task T3 is released shortly after the system starts. Although it’s
the lowest-priority task in the system, it begins execution immediately because no
other tasks have been released. Early in its execution, it acquires a lock on resource
R1. At about time t + 1.5, task T1 is released and preempts the lower-priority task,
T3. At time t + 3, task T2 is released but cannot execute because task T1 is still
executing. At some point after t + 3, task T1 attempts to acquire a lock on R1, but
blocks because it’s already locked. Because of this, T2 gains execution prece-
dence over T1 even though it has a lower priority. When T2 completes, T3 contin-
ues again until it releases R1, at which point T1 is finally able to resume.

Task T1 blocks
on resource R1

T1

T2 R1

T3

1 2 3 4 5 Time

Task T3 Task T2 Task T3


acquires a lock executes releases lock
on resource R1

⫽ preempted

Figure 1-10 Resource locking can lead to priority inversion. In a real-time system, this
scenario must be controlled, or avoided.

Bruno_Chapter1.indd 20 5/15/09 2:13:21 AM


REAL-TIME SCHEDULING 21

In a general-purpose computer system, this may be a common and acceptable


situation. In a real-time system, however, this violates the principal of task prior-
ity execution, and must be avoided. The time frame from shortly after t + 3, to
shortly after t + 5, represents unbounded latency that adds an unknown amount of
delay to the critical task, T1. As a result, real-time systems must implement some
form of priority inversion control, such as priority inheritance, to maintain for-
ward progress of critical tasks. This will be discussed later in the chapter; for now,
let’s continue our discussion on scheduling constraints.

Precedence
In many systems, real-time systems included, tasks cannot be scheduled in arbi-
trary order. There is often a precedence of events that govern which threads must
be scheduled first. Typically, the threads themselves imply the ordering through
resource sharing, or some form of communication, such as a locking mechanism.
One example is a system where a task T1 must wait for another task T2 to release
a lock on an object before it can begin execution. This act of task synchronization
must be performed at the OS kernel level so as to notify the scheduler of the task
precedence that exists.
In the example above the scheduler will block task T1, and will allow task T2 to
execute. When task T2 completes its processing and releases its lock on the syn-
chronized object that the two tasks share, the scheduler can dispatch task T1. The
task precedence dictated by the synchronization in this example must be obeyed
even if there are other processors in the system that are ready to execute waiting
tasks. Therefore, in this example, regardless of the number of available proces-
sors, task T1 will always wait for task T2 to complete and hence release task T1 to
begin.
Notation: T2 < T1, or T2 → T1 for immediate task precedence
Task precedence can get complex, as a system with multiple tasks (each with its
own dependencies) must be scheduled according to the precedence rules. Real-
time system designers must understand task precedence fully before a system
begins execution to ensure that real-time deadlines can be met. To do this, prece-
dence relationships can be predetermined and represented by a graph, such as the
one shown in Figure 1-11.
In this diagram, each node on the graph represents a task. The nodes at the top
must execute and complete first before threads below them can execute. These
rules are repeated at each level of the graph. For instance, the scheduler for the
tasks represented in Figure 1-11 will begin by dispatching task T2 to execute first.
Once T2 is complete, task T1 will execute, while tasks T3 and T4 are blocked.

Bruno_Chapter1.indd 21 5/15/09 2:13:22 AM


22 CHAPTER 1 REAL-TIME FOR THE REST OF US

T ⫽ thread T2
Thread # ⫽ order of creation
Order of creation ! ⫽ order of precedence Order
of
Precedence
T1

T3 T4

Figure 1-11 A directed acyclic graph helps to summarize task dependencies in a


system.

Once T1 completes, tasks T3 and T4 will be eligible to be dispatched. If there is


more than one processor ready, both tasks T3 and T4 can be scheduled to run
simultaneously—this graph does not indicate precedence between them.

Timing
Real-time tasks are labeled as such because they have time-related constraints,
usually to do with a deadline for processing. As a result, schedulers are concerned
with many time-related parameters to ensure that a task can complete on or before
its deadline. For instance, schedulers need to consider the following, per task:

Deadline: of course, understanding the task’s deadline (relative or absolute)


and its value is critical to determining if it can be scheduled feasibly.
Period: many real-time tasks need to execute at regular time intervals. Others
do not, and instead respond to events as they happen. The scheduler must distin-
guish each task’s type (periodic, aperiodic, and sporadic), along with the timing
characteristics that might apply. We’ll discuss periodic tasks in the next
section.
Release Time: important information when scheduling periodic tasks, to deter-
mine if a set of tasks can be scheduled feasibly.
The Variation in Releases Times: tasks vary slightly from period to period as to
when they will actually be eligible for execution.
Start Time: some tasks will not be able to execute as soon as they are released
(due to locks, higher-priority tasks running, and so on).
Execution Time: task cost functions need to know the best- and worst-case
execution times for a task.

Bruno_Chapter1.indd 22 5/15/09 2:13:22 AM


REAL-TIME SCHEDULING 23

Other parameters are calculated as a result of scheduling a given set of tasks,


such as:

Lateness: the difference between a task’s actual completion time, and its
deadline.
Tardiness: the amount of time a task executes after its deadline. This is not
always equal to the lateness value, as a task may have been preempted by
another task, which caused it to miss its deadline.
Laxity: the amount of time after its release time that a task can be delayed with-
out missing its deadline.
Slack Time: same as laxity (above). However, this term is sometimes used to
describe the amount of time a task can be preempted during its execution and
still meet its deadline.

Scheduling Algorithms
The three constraint sets above are directly used in scheduling algorithms to deter-
mine a feasible schedule for a set of real-time tasks. Feeding into the algorithm as
parameters are the set of tasks, T, to be scheduled; the set of processors, P, available
to execute them; and the set of resources, R, available for all tasks in the system.
Scheduling algorithms differ in their criterion in determining when, and for how
long, a task can execute on a processor. Real-time scheduling algorithms exist to
ensure that regardless of system load—or the amount of threads eligible to be
dispatched—the time-critical tasks of the system get ample processing time, at
the right time, to meet their deadlines. Let’s examine some of the high-level char-
acteristics of real-time schedulers.

Preemptive Versus Non-Preemptive Scheduling


To understand scheduling algorithms, we need to agree upon some basic con-
cepts. For instance, most operating systems allow a task to be assigned a priority.
Higher-priority tasks, when ready to execute, will be given precedence over
lower-priority tasks. An algorithm is said to be preemptive if a running task can be
interrupted by another, higher priority task. However, there are scheduling algo-
rithms in the real-time world that are non-preemptive [Liu00]. In this case, once a
thread executes, it continues to do so until it completes its task.
Some algorithms allow a mixture of preemptive and non-preemptive tasks with
classes of thread priorities, and specific support for real-time tasks. On a

Bruno_Chapter1.indd 23 5/15/09 2:13:22 AM


24 CHAPTER 1 REAL-TIME FOR THE REST OF US

multi-processor system, this hybrid approach works well, since relatively long-
running non-preemptive tasks do not prevent the system from performing other
tasks, as long as there are more processors available than real-time tasks. The
advantage to the real-time programmer is increased control over system behavior,
which results in a more deterministic system overall.

Context Switching
In addition to the added determinism it provides, another reason to choose a non-
preemptive scheduler is to avoid unforeseen context switches, which occur when
one thread preempts another thread that’s already running. The operating system
must expend processor time executing code that saves the state of the already run-
ning thread, and then resets internal data structures and processor registers to
begin execution of the preempting thread so that it can begin execution. This
entire preemption process is summarized as dispatching, as mentioned earlier in
this chapter. The time it takes a particular system to perform this preemption task
is called dispatch latency, and can interfere with a system’s ability to respond to
an event by its deadline.
As a system becomes increasingly busy, with more threads competing for pro-
cessing time, a considerable percentage of time can be spent dispatching threads,
resulting in an additive effect in terms of dispatch latency. A system that spends
more time dispatching threads than actually performing real work is said to be
thrashing. Real-time systems must guarantee that even under high system load,
thrashing due to context switches will not occur, or that it at least won’t interfere
with the high-priority threads performing real-time processing in the system. OS
kernels with hybrid preemption/non-preemption support are useful in these cases,
allowing real-time processing to be guaranteed on a general-purpose system.

Dynamic and Static Scheduling


One way to control context switching while still allowing preemption is through
static scheduling. For instance, in a dynamically scheduled system, tasks are dis-
patched on the fly as the system is running, based upon parameters that may
change over time (such as task priority). All decisions as to which task to schedule
at each point in time are made while the system is running, and are based on the
system state at certain checkpoints. This is a common scheduling algorithm used
in many popular operating systems.
With static scheduling, however, the execution eligibility of a task never changes
once it’s assigned. The important scheduling parameters for each task, such as the
priority, are determined when those tasks first enter the system based upon the

Bruno_Chapter1.indd 24 5/15/09 2:13:23 AM


REAL-TIME SCHEDULING 25

state of the system and its current set of tasks. For instance, a static scheduling
algorithm may assign a priority to a new task based on its period (defined below)
relative to the periods of the other tasks in the system. In this way, a static schedul-
ing algorithm can be used either offline or online (while the system is running).

Task Migration
Another important parameter to real-time task scheduling is the ability of a task to
be executed by different processors in a multiprocessor system. For instance, in
some systems, once a task begins execution on a particular processor, it cannot
migrate to another processor even if it’s preempted, and another processor is idle.
In this type of system, task migration is not allowed.
However, many systems do allow tasks to migrate between available processors
as tasks are preempted, and different processors become available. This type of
system supports dynamic task migration, as there are no restrictions placed on
tasks in relation to processors. Of course, there are systems that fall in between,
which support restricted task migration. One example is a system with many pro-
cessors, where certain tasks are restricted to a subset of total processors within the
system. The remaining processors may be dedicated to a task, or small set of tasks,
for example. Another example might be that on multiprocessor/multi-board
systems, the OS might limit task migration to CPUs on the same board to take
advantage of locality of reference.
An example of a common real-time operating system that supports restricted
task migration is Solaris. Solaris allows you to define individual processor sets,
assign physical processors (or processor cores) to the defined sets, and then
dedicate a processor set to a particular application. That processor set will then
execute only the threads (tasks) within that application, and no others. The tasks
will be able to migrate across the physical processors within the set, but not the
others.

Periodic, Aperiodic, and Sporadic Tasks


Earlier in this chapter, we discussed relative and absolute deadlines, and com-
pared the differences using some examples. A task that is released at a regular
time interval is often called a periodic task. An aperiodic task has no known
period; external events are generated asynchronously at unknown, often random,
time intervals. To be precise, with an aperiodic task, the time interval between
releases varies, but is always greater than or equal to zero:

For aperiodic task, ti: ∀i∈N, (ri + 1 − ri ) ≥ 0

Bruno_Chapter1.indd 25 5/15/09 2:13:23 AM


26 CHAPTER 1 REAL-TIME FOR THE REST OF US

In comparison, for a periodic task, the length of the time interval between any two
adjacent releases is always constant:

For periodic task, ti: ∀i∈N, (ri + 1 − ri ) = C

Whether a thread is periodic or aperiodic can make a difference to the scheduler,


as one is to do work on a known time interval, and the other is released when an
event notification arrives—such as a network message—at unknown points in
time. It’s obvious that if all threads in a system were periodic, it would be easier to
work out a schedule than if all threads were aperiodic.
A system with multiple aperiodic threads must be carefully planned and measured
as unforeseen events, and combinations of events, can occur at any time. This situ-
ation may seem orthogonal to the real-time requirement of predictability, but with
careful consideration of thread priorities, it’s mathematically possible to schedule
such a system. Later in this chapter, we’ll examine how the most common sched-
uling algorithms handle aperiodic tasks through what’s called a sporadic server.
A common example of a sporadic task in a hard real-time system is the autopilot
control in an airplane’s flight control system. The human pilot may switch the
autopilot on, and subsequently off, at specific points in time during a flight. It’s
impossible to determine precisely when these points in time may occur, but when
they do, the system must respond within a deadline. It would certainly be consid-
ered an error condition if, when the pilot switched off the autopilot, that the system
took an unduly large amount of time to give the human pilot control of the
aircraft.
A sporadic task is one where the length of the time interval between two adjacent
releases is always greater than or equal to a constant (which itself is non-zero):

For sporadic task, ti: ∀i∈N, (ri + 1 − ri ) ≥ K

Execution Cost Functions


When scheduling real-time tasks, it’s necessary to have a mathematical basis upon
which to make scheduling decisions. To do this, we need to take into account the
following calculations of task execution cost:

Total completion time, tc = max(ƒi ) − min(ai )


This cost function calculates the overall completion time for a set of tasks by
subtracting the time the last task finished from the time the first task started;
note that these can be different tasks.

Bruno_Chapter1.indd 26 5/15/09 2:13:42 AM


REAL-TIME SCHEDULING 27

if di > 0 and fi > di then 1 else 0


Late task, late(ti) = { if Di > 0 and Ci > Di then 1 else 0

This function returns the value 1, indicating true, if the task’s finish time exceeds
its absolute deadline, or if the task’s completion time exceeds its relative dead-
line, depending upon the type of deadline the task has.
n
Number of late tasks, Nlate = ∑ late(ti )
i =1

This function calculates the total number of tasks that miss their deadline in a
given real-time system with n tasks. Note: To simplify the equations and the
discussion going forward, let’s define a task’s deadline, di, where di equals its
absolute deadline di when a task has an absolute deadline, or di = ai + Di when a
task has a relative deadline.
Maximum lateness, Lmax = max(fi − di ): this function calculates the task with
the maximum lateness (missed its deadline by the greatest amount of time)
using di as we’ve just defined it. Note that this value can be negative (when all
tasks finish before their deadlines), or positive.

1⎛ n ⎞
Average response time, Ravg = ∑ Ci
n ⎜⎝ i =1 ⎟⎠

This function calculates the average response time for a given real-time system
by dividing the sum of all task completion times by the total number of tasks in
the system.

Classification of Real-Time Schedulers


Let’s look now at the common types of schedulers used in real-time systems.
We’ve already explored some features of scheduling algorithms in general, such
as preemption, static and dynamic scheduling, and support for aperiodic and peri-
odic tasks. Real-time systems go further in breaking down task scheduling
For instance, real-time schedulers can be broken down into two overall categories:

Guarantee-Based: these algorithms are often static, often non-preemptive,


and rigid to ensure that all tasks can complete their work by their given dead-
line. In dynamic systems, conservative measurements are typically used to
ensure that the arrival of new tasks will not cause any existing tasks to miss

Bruno_Chapter1.indd 27 5/15/09 2:13:46 AM


28 CHAPTER 1 REAL-TIME FOR THE REST OF US

their deadlines as a result. Often, these algorithms will err on the side of not
allowing a new task to start if there is a chance it can disrupt the system. This is
done to avoid a domino effect, where the introduction of a new task causes all
existing tasks to miss their deadlines. This pessimistic approach can some-
times mean that tasks may be blocked from starting that would not have caused
a problem in reality.
Best-Effort Based: these algorithms are dynamic, more optimistic, and less
conservative, when it comes to new task arrival. These schedulers are typically
used in systems with soft real-time constraints, such that a missed deadline due
to new task arrival is generally tolerable. They are classified a “best-effort”
because these schedulers almost always allow new tasks into the system, and
will do their best to ensure that all tasks complete their processing on or close
to their deadlines. This results in a very responsive, efficient, real-time system
that is best suited for soft real-time tasks where hard guarantees are not
needed.

Within both classifications, the different algorithms must be one of the following
to be considered as real-time:

Feasible: sometimes called an heuristic algorithm, this scheduler searches for a


feasible schedule whereby all tasks complete their work at or before their
respective deadlines. A feasible schedule still guarantees the real-time behav-
ior of the system. A schedule is deemed infeasible if one or more tasks within a
real-time system miss a deadline.
Optimal: an optimal scheduling algorithm is one that will always find a
feasible schedule (all tasks complete on or before their deadlines) if one
exists. An optimal algorithm may not always produce the best schedule, but
it will always produce a schedule that meets every task’s deadline if one is
possible.

To achieve a feasible schedule for tasks in a hard real-time system, there are three
common approaches often used. These are:

Clock-Driven: sometimes called time-driven, this approach schedules task


execution based on known time qualities of each task in the system before the
system starts. Typically, all decisions are made offline, and scheduling activi-
ties are performed during well-known points in time while the system is run-
ning. The result is a guaranteed real-time schedule with predictable execution,
where the scheduler operates with very little overhead. The time-based
quality(s) used to make scheduling decisions vary among the different clock-
driven algorithms often used.

Bruno_Chapter1.indd 28 5/15/09 2:13:50 AM


REAL-TIME SCHEDULING 29

Weighted Round-Robin: similar to round-robin schedulers used in time-sharing


systems, this approach applies a different weight value to each task in the sys-
tem based upon some criterion. Tasks with higher weight are given more execu-
tion time, or higher priority, resulting in their ability to complete their work
sooner. This approach is only suitable in certain types of systems (such as those
with very little interdependency amongst the individual tasks in the system).
Priority-Driven: sometimes called event-driven, scheduling decisions are made
when important system events occur (such as the release of a task, the availabil-
ity of a resource, an IO event, and so on) with the intent to keep resources
as busy as possible. With this approach, tasks are given a priority, placed in
priority-ordered queues when released, and are then dispatched at the earliest
point in time that a processor is free. No task is unduly delayed when an idle
processor exists (a trait that can be a liability in some cases). Algorithms within
this scheduling class are further sub-classed as fixed-priority (where task priori-
ties and execution orders remain constant during system execution), and
dynamic-priority (where tasks’ priorities can change, and all scheduling is done
online while the system is running).

There are many different real-time scheduling algorithms in existence, each of


which works best with certain types of systems. For instance, some schedulers
analyze tasks offline, before the system begins to execute. This type of system
requires all tasks be known before execution, and that no new tasks be introduced
while the system is in a time-critical mode.
Other schedulers work while a system is online, and must contain additional logic to
ensure that as new tasks enter the system, a new feasible schedule can be generated.
In either offline or online scenarios, some schedulers work only with fixed-priority
tasks, while others allow tasks’ priorities to change while the system is running.
The dynamic-priority, online schedulers tend to be the most complex and least
predictable, while static-priority schedulers tend to be best for hard real-time sys-
tems. Let’s look at some common algorithms that fall into these categories, and
examine their characteristics:

First-Come-First-Served (FIFO): sometimes referred to as a first-in-first-out


(FIFO) schedule, this is a dynamic-priority algorithm that schedules tasks based
on their release times (execution eligibility).
Earliest-Deadline-First Scheduler (EDF): in this dynamic preemptive sched-
uler, at any instant the executing task is the task with the closest deadline.
Shortest-Execution-Time-First Scheduler (SETF): in this non-preemptive
scheduler, the task with the smallest execution time is scheduled first.

Bruno_Chapter1.indd 29 5/15/09 2:13:50 AM


30 CHAPTER 1 REAL-TIME FOR THE REST OF US

Least-Slack-Time Scheduler (LST): tasks are given higher priority based on


their slack time. In this dynamic-priority algorithm, task slack time is calcu-
lated as the task’s deadline minus the current point in time minus the time
required to complete processing. The task with the smallest slack time is given
highest priority. Slack times—and hence priorities—are recalculated at certain
points in time, and tasks are subsequently rescheduled.
Latest-Release Time-First Scheduler (LRT): sometimes called reverse-EDF,
tasks are scheduled backward, in the sense that release times are treated as
deadlines, and deadlines are treated as release times. The scheduler works
backwards in time and assigns tasks to processors based on their deadlines,
working back to the start of execution. Think of it as reading from right to left.
This scheduler performs all scheduling offline, before the system begins to
execute.
Rate-Monotonic Scheduler (RM): the inverse of a task’s period is called its
rate. Used in systems with periodic tasks and static priorities, this fixed-priority
preemptive algorithm assigns higher priorities to tasks with shorter periods
(higher rates).
Deadline-Monotonic Scheduler (DM): in this static, fixed-priority preemptive
scheduler, the task with the shortest relative deadline is scheduled first. In a
real-time system, when each task’s relative deadline equals its period, the RM
and DM schedulers generate the same schedule.

In some systems, such as those that run both real-time and general-purpose appli-
cations together, a scheduling algorithm is used in conjunction with a partitioning
scheme to achieve optimal system behavior. With this approach, tasks are parti-
tioned, or grouped, based upon certain criteria. The partitioning scheme can be
either fixed, or adaptive:

Fixed-Partition Scheduling: this is a dynamic, preemptive, scheduler that


assigns time budgets, in terms of total processing time allowed, to different
groups of tasks called partitions. Each partition, as a whole, is bounded not to
exceed its total budget of processor time (i.e., 10% of the CPU).
Adaptive-Partition Scheduling: this is a dynamic, preemptive, scheduler where
a percentage of the processor time (and sometimes system resources) are
reserved for a particular group of tasks (partition). When the system reaches
100% utilization, hard limits are imposed on the non-real-time partition in order
to meet the needs of the real-time tasks. When the system is less than 100%
utilized, however, active partitions will be allowed to borrow from the budget
reserved for other, non-active, partitions.

Bruno_Chapter1.indd 30 5/15/09 2:13:51 AM


REAL-TIME SCHEDULING 31

The intent of the Java Real-Time System is to hide this complexity from you.
However, to truly appreciate its implementation, and to understand why your Java
applications behave as they do within it, you should at least have a cursory under-
standing of the theory behind its implementation.
Both the RTSJ and Sun’s Java RTS are meant to provide real-time behavior to Java
applications even on general-purpose hardware with a real-time OS. However, this
is a deviation from what has been classically accepted as a real-time system. In the
past, you had to write code in a language designed for real-time applications and
use dedicated, special-purpose hardware to run them on. Again, to gain a true
appreciation of the real-time space, and the problems that Java RTS had to over-
come, let’s take a brief look at some common real-time languages and operating
systems.

Multi-Core Processors and Scheduling


For the most part, modern operating systems treat individual processor cores as
individual processors themselves. This is an accurate representation, as each core is
a complete processor in its own right, capable of acting like an independent
processor—albeit sometimes with a shared on-chip cache. Therefore, it’s not
required for the OS to treat individual cores any differently than individual
processors.
However, some OS kernels do take special care in scheduling threads on separate
cores as opposed to separate physical processors. Solaris 10, for instance,
will schedule eligible threads to distribute them across physical processors first,
then across the cores of individual processors [McDougall07]. For instance,
on a system with two dual-core processors, Solaris will dispatch the first thread
on core 1 of processor 1, and the second thread on core 1 of processor 2 (see
Figure 1-12).

Processor 1 Processor 2
C1 T1 C1 T2

C2 -- C2 --

C ⫽ core
T ⫽ thread

Figure 1-12 The Solaris kernel attempts to balance threads across CPUs to help
with heat dissipation.
continued

Bruno_Chapter1.indd 31 5/15/09 2:13:51 AM


32 CHAPTER 1 REAL-TIME FOR THE REST OF US

Processor 1 Processor 2

C1 T1 C3 T5 C1 T2 C3 T6

C2 T9 C4 T13 C2 T10 C4 T14

Processor 3 Processor 4

C1 T3 C3 T7 C1 T4 C3 T8

C2 T11 C4 T15 C2 T12 C4 T16

C ⫽ core
T ⫽ thread

Figure 1-13 Solaris kernel threads spread equally across all available cores.
From this point onward, additional threads will be scheduled on the next
available (free) core.

Threads 3 and 4 will be dispatched to core 2 of processor 1, and core 2 of processor 2,


respectively. In this case, even though thread 2 could have been scheduled on core 1
of processor 1, this would upset the balance. The intent is to distribute running
threads across physical processors and their cores evenly. For instance, on a system
with four quad-core processors, with sixteen dispatched and running threads, the
thread-to-processor/core distribution should look as shown in Figure 1-13.
This distribution of threads over available cores has little bearing on our real-time
discussion, although it’s important to know that it does occur.

Real-Time Operating Systems


To meet the needs of the most demanding real-time systems, specialized operat-
ing systems are available. Besides having the required features to support predict-
able task execution for time-critical applications, the real-time OS will also have
its own real-time constraints. For example, core scheduling and other OS-specific
functionality must behave in predictable, measurable, ways, with high efficiency
and low latency. In other words, the OS and its scheduling activities must never
contribute to unbounded task latency, or be unpredictable in any sense.
A real-time OS has thread schedulers built-in that support real-time systems. Most
often, these operating systems allow programmers to control the computer hard-
ware at the lowest level, including processor interrupts, physical memory access,
and low-level input/output (I/O) processing. This is done so that the real-time
application developer can remove as much of the non-deterministic behavior and
end-to-end latency found in general-purpose operating systems.

Bruno_Chapter1.indd 32 5/15/09 2:14:00 AM


REAL-TIME SCHEDULING 33

Many real-time operating systems target embedded systems with dedicated func-
tionality and limited hardware resources. This means that these systems are not
meant to be general-purpose systems, and using a real-time OS proves to be a
valuable tool in these cases. However, as mentioned before in this chapter, with
the continuing advances in hardware capabilities at lower cost, the need for spe-
cialized hardware and operating systems has diminished significantly. A dedicated
real-time OS comes at a high cost relative to the general-purpose operating sys-
tems available today. Many argue that the state of the industry has reached a point
that this extra cost is no longer justified. However, recall that while adding addi-
tional, more powerful, hardware can help improve raw performance and through-
put, it almost never makes an unpredictable system behave predictably.
Regardless, there are instances, such as with embedded systems, where a real-time
OS continues to be the only option. While this book does not go into detail regard-
ing real-time operating systems, it’s important to know that they do exist and serve
a specialized purpose. Real-time applications typically require the same set of ser-
vices from the OS—such as disk IO, networking support, a file system, user IO,
and so on—as general purpose applications do. However, the real-time applica-
tion requires its OS to make guarantees that are both measurable and predictable.

RT-POSIX Operating System Extensions


With the intent to unify the real-time application and OS space, the Real-Time
Portable Operating System based-on Unix (RT-POSIX 1003.1b) standard was
created. POSIX is a standard that has been very successful and widely adopted in
a wide-range of OS implementations, for both mission-critical and general-
purpose computing. RT-POSIX defines an extension to it that addresses the needs
of hard and soft real-time systems.
The standard defines a minimum set of features that a compliant OS must imple-
ment. Additional features can be implemented, provided that they do not conflict
with or hereby negate the required features. For example, RT-POSIX-compliant
operating systems must have the following traits:

Preemption: true task preemption must be supported using task priority rules
that are strictly obeyed.
Priority Inversion Control: although it cannot guard well against deadlocks,
priority inheritance ensures that lower-priority threads will never be able to
block higher-priority threads due to classic priority inversion.
Periodic, Aperiodic, and Sporadic Threads: the POSIX standard requires only
processes be implemented. For real-time applications, threads of different

Bruno_Chapter1.indd 33 5/15/09 2:14:04 AM


34 CHAPTER 1 REAL-TIME FOR THE REST OF US

priority may need to run to perform a task. For this reason, the RT-POSIX stan-
dard requires the OS be able to schedule tasks down to the thread level, and that
applications be able to create and destroy those threads. Underlying OS threads
must be able to support the various types of task release events common to
real-time applications. For instance, a thread should be able to specify its period
and then rely on the OS to wake it up at precise time boundaries that match that
period. Simply performing a call to “sleep” from within the task’s code (as is
done in a non-real-time OS) is not sufficient.
High-Resolution Timers: such timers should be made available to real-time
applications, as well as the real-time OS itself so that it can dispatch threads
with as little latency and jitter as possible. For example, an OS scheduler with a
10-millisecond tick size will, at best, experience up to 10 milliseconds latency
during thread dispatch processing. In general, the larger the tick count, the
higher the max latency and jitter values will grow. Both are qualities to be
avoided in real-time systems. The RT-POSIX standard states that up to 32 timers
per process must be supported, and that timer overruns (when a timer goes
beyond its chosen duration) be recorded.
Schedulers: the kernel needs to support both deadline-monotonic and rate-
monotonic deadline scheduling in order to support the common real-time
scheduling algorithms such as weighted round-robin, fixed-priority, and
earliest-deadline-first scheduling. The type of scheduler used can be defined
down to the thread level, where two threads of the same process may be sched-
uled differently.
Scheduled Interrupt Handling: the ability to create a preemptable task that
processes low lever device interrupts. This is sometimes called a software inter-
rupt. In contrast, a general-purpose OS typically handles these events com-
pletely itself, making the data or status available through some other means.
Synchronous and Asynchronous IO: synchronous IO operations provide real-
time tasks more control over IO-related tasks, such as file and network opera-
tions. Asynchronous IO allows the system to progress task execution while IO
is occurring, or waiting to occur. For instance, a task that reads a network packet
can process the packet’s payload even while it waits for the next packet to
arrive.
Inter-Task Communication: to facilitate predictable, low-latency, communi-
cation between tasks, queues should be provided at the OS level. This also
ensures fast, consistent, and measurable performance, with support for mes-
sage prioritization. These queues are sometimes made available to tasks both
local to the system, and remote. Regardless, message delivery must be priori-
tized, and at least eight prioritized signals are supported per process.

Bruno_Chapter1.indd 34 5/15/09 2:14:04 AM


FURTHER READING 35

Priority Inheritance: to guard against deadline misses due to priority inversion


(where a lower-priority task’s priority is raised above that of a higher-priority
task) priority inheritance needs to be implemented at the kernel level, or at least
emulated.
Resource Quotas: the ability to monitor and control the usage of system
resources such as memory and processor time to ensure the system behaves in a
predictable way even when under heavy load.
Memory Sharing: shared memory (between processes) and memory-mapped
files must be supported.
Memory Locking: applications must be able to control the memory residency
of their code sections through functions that will either lock all of its code, or
only the portions specified.
Real-Time File System: file systems that ensure files are made up of contiguous
disk blocks, pre-allocate files of fixed size to be used on-demand while the sys-
tem is running, and offer sequential access, provide the most predictable behav-
ior and timing characteristics.
Synchronization: OS primitives that support efficient resource sharing between
tasks with priority inheritance, and ceiling priority (both of which are protocols
to control or avoid thread priority inversion).

Further Reading
Much of the information for this chapter was gathered from papers and texts on
the subject of real-time systems and scheduling theory. For readers who are inter-
ested, below is a list of reading material that will help build a complete foundation
for real-time theory and practice:
[Buttazzo05] Buttazzo, Georgia C., Hard Real-Time Computing Systems.
Springer, 2005.
[Klein93] Klein, Mark, et al., A Practitioner’s Guide to Real-Time Analysis.
Kluwer Academic Publishers, 1993.
[Layland73] Liu, C.L. and Layland, James W., Scheduling Algorithms for Multi-
programming in a Hard Real-Time Environment. Journal of the ACM, 1973
(Available at http://portal.acm.org/citation.cfm?id=321743).
[Liu00] Liu, Jane W. S., Real-Time Systems. Prentice Hall, 2000.
[McDougall07] Mauro, Jim, McDougall, Richard, Solaris Internals. Prentice
Hall, 2007.

Bruno_Chapter1.indd 35 5/15/09 2:14:04 AM


Google
Bookmarks Delicious Digg Facebook StumbleUpon Reddit Twitter

Java_Rock_Star_CH_Openers.indd 7 6/18/09 1:52:33 PM


Erica Sadun

The iPhone Developer’s


Cookbook
The iPhone and iPod touch aren’t just attracting millions of new users; their
breakthrough development platform enables programmers to build tomorrow’s killer AVAILABLE
applications. If you’re getting started with iPhone programming, this book brings • BOOK: 9780321555458
together tested, ready-to-use code for hundreds of the challenges you’re most likely • SAFARI ONLINE
to encounter. Use this fully documented, easy-to-customize code to get productive • EBOOK: 0321591186
fast—and focus your time on the specifics of your application, not boilerplate tasks. • KINDLE: COMING SOON

Leading iPhone developer Erica Sadun begins by exploring the iPhone delivery
platform and SDK, helping you set up your development environment, and showing About the Author
how iPhone applications are constructed. Next, she offers single-task recipes for the
Erica Sadun has written, coauthored,
full spectrum of iPhone/iPod touch programming jobs:
and contributed to about three dozen
books about technology, particularly
• Utilize views and tables
in the areas of programming, digital
• Organize interface elements
video, and digital photography. An
• Alert and respond to users
unrepentant geek, Sadun has never met
• Access the Address Book (people), Core Location (places), and Sensors (things)
a gadget she didn’t need. Her checkered
• Connect to the Internet and Web services
past includes run-ins with NeXT,
• Display media content
Newton, iPhone, and myriad successful
• Create secure Keychain entries
and unsuccessful technologies. When
• And much more
not writing, she and her geek husband
parent three adorable geeks-in-training,
You’ll even discover how to use Cover Flow to create gorgeous visual selection
who regard their parents with restrained
experiences that put scrolling lists to shame!
bemusement.
This book is organized for fast access: related tasks are grouped together, and you can
jump directly to the right solution, even if you don’t know which class or framework to
use. All code is based on Apple’s publicly released iPhone SDK, not a beta. No matter
what iPhone projects come your way, The iPhone Developer’s Cookbook will be
your indispensable companion.

informit.com/aw

Java_Rock_Star_CH_Openers.indd 8 6/18/09 1:52:34 PM


02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 37

2
Views

P retty much everything that appears on the iPhone’s screen is a view.Views act like
little canvases that you can draw on with colors, pictures, and buttons.You can drag them
around the screen.You can resize them.You can layer them. In this chapter, you discover
how to design and build screen content using Cocoa Touch and UIViews.You learn
about view hierarchy, geometry, and animation, and find out how to combine event
feedback from UITouches into meaningful UIView responses.There’s so much that
UIViews can do that a single chapter has no hope of covering the entire class with the
thoroughness it deserves. Instead, this chapter introduces essential functionality and
recipes that you can use as a starting point for your own UIView exploration.

UIView and UIWindow


The iPhone rule goes like this: one window, many views. If you keep that idea in mind,
the iPhone interface design scenario simplifies. Metaphorically speaking, UIWindow is the
TV set, and UIViews are the actors on your favorite show.They can move around the
screen, appear, and disappear, and may change the way they look and behave over time.
The TV set, on the other hand, normally stays still. It has a set screen size that doesn’t
change even if the virtual world you see through it is practically unlimited.You may
even own several TVs in the same household (just like you can create several UIWindow
instances in the same application), but you can watch just one at a time.
UIViews are GUI building blocks.They provide visual elements that are shown
onscreen and invite user interaction. Every iPhone user interface is built from UIViews
displayed within one UIWindow, which is itself a specialized kind of UIView.The win-
dow acts a container; it is the root of the display hierarchy. It holds all the visible applica-
tion components within itself.The following sections will give you just a taste of the
kind of ways you can control and manipulate views, their hierarchy, and their geometry.

Hierarchy
A tree-based hierarchy orders what you see on your iPhone screen. Starting with the
main window, views are laid out in a specifically hierarchical way. All views may have
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 38

38 Chapter 2 Views

children, called subviews. Each view, including the root window, owns an ordered list of
these subviews.Views might own many subviews; they might own none.Your application
determines how views are laid out and who owns whom.
Subviews display onscreen in order, always from back to front. And because the iPhone
supports view transparency, this works exactly like a stack of animation cells—those trans-
parent sheets used to create cartoons. Only the parts of the sheets that have been painted
are shown.The clear parts allow any visual elements behind that sheet to be seen.
Figure 2-1 shows a little of the layering used in a typical window. Here you see the
window that owns a UINavigationController-based window.The window (repre-
sented by the clear, rightmost element) owns a Navigation subview, which in turn owns
two subview buttons (one left and one right) and a table.These items stack together to
build the GUI.

Figure 2-1 Adding subview hierarchies


allows you to build complex GUIs.

Notice how the buttons appear over the navigation bar and how the table is sized so
that it won’t obscure either the buttons or bar.The button frames are small, taking up
very little space onscreen.The table frame is large, occupying the majority of screen
space. Here are some ways you can manage subviews in your programs:
n To add a subview, use a call to [parentView addSubview:child]. Newly added
subviews are always frontmost on your screen.
n Query any view for its children by asking it for [parentView subviews].This
returns an array of views, ordered from back to front.
02_0321555457_ch02.qxd 10/23/08 1:22 PM Page 39

UIView and UIWindow 39

n Remove a subview from its parent with [childView removeFromSuperview].


n Reorder subviews using [parentView exchangeSubviewAtIndex:i
withSubviewAtIndex:j]. Move subviews to the front or back using
bringSubviewToFront: or sendSubviewToBack:.
n Tag your subviews using setTag:.This identifies views by tagging them with a
number. Retrieve that view from the child hierarchy by calling viewWithTag: on
the parent.

Note
You can tag any instance that is a child of UIView, including windows and controls. So if
you have many onscreen buttons and switches, for example, add tags so that you can tell
them apart when users trigger them.

Geometry and Traits


Every view uses a frame to define its boundaries.The frame specifies the outline of the
view: its location, width, and height.You define the frame rectangle using Core Graphics
structures. For frames, this usually means a CGRect rectangle made up of an origin
(a CGPoint, x and y) and a size (a CGSize, width and height). Here are some quick facts
about these types.

CGRect
The CGRect structure defines an onscreen rectangle. It contains an origin (rect.origin)
and a size (rect.size).These are CGRect functions you’ll want to be aware of:
n CGRectMake(origin.x, origin.y, size.width, size.height) defines
rectangles in your code.
n NSStringFromCGRect(someCGRect) converts a CGRect structure to a formatted
string.
n CGRectFromString(aString) recovers a rectangle from its string representation.
n CGRectInset(aRect) enables you to create a smaller or larger a rectangle that’s
centered on the same point. Use a positive inset for smaller rectangles, negative for
larger ones.
n CGRectIntersectsRect(rect1, rect2) lets you know whether rectangle
structures intersect. Use this function to know when two rectangular onscreen
objects overlap.
n CGRectZero is a rectangle constant located at (0,0) whose width and height are
zero.You can use this constant when you’re required to create a frame but you’re still
unsure what that frame size or location will be at the time of creation.

CGPoint and CGSize


Points refer to locations defined with x and y coordinates; sizes have width and height.
Use CGPointMake(x, y) to create points. CGSizeMake(width, height) creates
02_0321555457_ch02.qxd 10/23/08 1:22 PM Page 40

40 Chapter 2 Views

sizes. Although these two structures appear to be the same (two floating-point values),
the iPhone SDK differentiates between them. Points refer to locations. Sizes refer to
extents.You cannot set myFrame.origin to a size.
As with rectangles, you can convert them to and from strings:
NSStringFromCGPoint(), NSStringFromCGSize(), CGSizeFromString(), and
CGPointFromString() perform these functions.

Defining Locations
You can define a view’s location by setting its center (which is a CGPoint) or bounds
(CGRect). Unlike the frame, a view’s bounds reflect the view’s frame in its own coordi-
nate system. In practical terms, that means the origin of the bounds is (0.0, 0.0), and its
size is its width and height.
When you want to move or resize a view, update its frame’s origin, center, or size.You
don’t need to worry about things such as rectangular sections that have been exposed or
hidden.The iPhone takes care of the redrawing.This lets you treat your views like tangi-
ble objects and delegate the rendering issues to Cocoa Touch. For example
[myView setFrame:CGRectMake(0.0f, 50.0f, mywidth, myheight)];

Transforms
Standard Core Graphics calls transform views in real time. For example, you can apply
clipping, rotation, or other 2D geometric effects. Cocoa Touch supports an entire suite of
affine transforms (translate, rotate, scale, skew, and so on).The drawRect: method for
any UIView subclass provides the entry point for drawing views through low-level Core
Graphics calls.

Note
When calling Core Graphics functions, keep in mind that Quartz lays out its coordinate
system from the bottom left, whereas UIViews have their origin at the top left.

Other View Traits


In addition to the physical screen layout, you can set the following view traits among
others:
n Every view has a translucency factor (alpha) that ranges between opaque and
transparent. Adjust this by issuing [myView setAlpha:value], where the alpha
values falls between 0.0 (fully transparent) and 1.0 (fully opaque).
n You can assign a color to the background of your view. [myView
setBackgroundColor:[UIColor redColor]] colors your view red.

View Layout
Figure 2-2 shows the layout of a typical iPhone application screen. For current releases of
the iPhone, the screen size is 320x480 pixels in portrait mode, 480x320 pixels in landscape.
At the top of the screen, whether in landscape or portrait mode, a standard status bar
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 41

UIView and UIWindow 41

occupies 20 pixels of height.To query the status bar frame, call [[UIApplication
sharedApplication] statusBarFrame].
If you’d rather free up those 20 pixels of screen space for other use, you can hide the
status bar entirely. Use this UIApplication call: [UIApplication sharedApplication]
setStatusBarHidden:YES animated:NO].Alternatively, set the UIStatusBarHidden
key to <true/> in your application Info.plist file.
To run your application in landscape-only mode, set the status bar orientation to
landscape. Do this even if you plan to hide the status bar (that is, [[UIApplication
sharedApplication] setStatusBarOrientation:
UIInterfaceOrientationLandscapeRight]).This forces windows to display side to
side and produces a proper landscape keyboard.
The UIScreen object acts as a stand in for the iPhone’s physical screen ([UIScreen
mainScreen]).The screen object maps view layout boundaries into pixel space. It
returns either the full screen size (bounds) or just the rectangle that applies to your
application (applicationFrame).This latter takes the size of your status bar and, if used,
any toolbars/navigation bars into account.
By default, UINavigationBar, UIToolbar, and UITabBar objects are 44 pixels in
height each. Use these numbers to calculate the available space on your iPhone screen
and lay out your application views when not using Interface Builder’s layout tools.

Figure 2-2 On current generations of the iPhone, the status bar is


20 pixels high, often followed below by a 44-pixel-high navigation bar. If you
use a toolbar at the bottom of your screen, that will also occupy 44 pixels.
It helps to use Photoshop or some other image layout program to design
your screens taking these geometries into account.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 42

42 Chapter 2 Views

Gestures
Views intercept user touches.This integration between the way things look and the way
things react enables you to add a meaningful response to taps, drags, and what have you.
Adding touch handlers like touchesBegan: withEvent: to your views allows you to
intercept user touches, determine the phase of the touch (the equivalent of mouse down,
mouse dragged, mouse up), and produce feedback based on those touches.
The UITouch class tells you where the event took place (locationInView:) and the
tap count (tapCount), which is vital for distinguishing between single- and double-taps.
Several recipes in this chapter demonstrate how to use these gesture responses and how
to integrate view geometry and hierarchy into your applications for enticing, layered,
direct-manipulation interfaces.

Recipe: Adding Stepwise Subviews


Expand your view hierarchy by calling addSubview:.This adds a subview to some other
view. Recipe 2-1 shows a simple UIViewController’s loadView method that defines a
series of stepped subviews. It demonstrates the basics of allocating, framing, and adding views.
These subviews are not nested, in that they all belong to the same parent.They’re
indented so that you can see them all at once.The indentation uses the handy
CGRectInset() function. Pass it a rectangle (using the CGRect structure) and two
insets—horizontal and vertical—and it returns the inset, centered rectangle. Here, each
subview is inset from its parent or sibling’s frame by 32 pixels on each side.
In their simplest form, views are little more than transparent placeholders. Coloring
the view backgrounds distinguishes one view from another in the absence of meaningful
content (see Figure 2-3). It’s a useful trick when trying to test layouts before committing
to an actual design.
Always keep your coordinate system in mind.When working with view hierarchy,
you must define a view’s frame in its parent’s coordinate system.The example in
Recipe 2-1 requests the application frame to lay out the main view and then resets its
origin to (0, 0). Resetting the origin updates the frame from the screen’s to the main
view’s coordinate system.This reset forms the basis for the view layout that follows.

Recipe 2-1 Adding Nested Subviews


- (void)loadView
{
// Create the main view
CGRect appRect = [[UIScreen mainScreen] applicationFrame];
contentView = [[UIView alloc] initWithFrame:appRect];
contentView.backgroundColor = [UIColor whiteColor];

// Provide support for autorotation and resizing


contentView.autoresizesSubviews = YES;
contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
➥UIViewAutoresizingFlexibleHeight);
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 43

Recipe: Adding Stepwise Subviews 43

Recipe 2-1 Continued


self.view = contentView;
[contentView release];

// reset the origin point for subviews. The new origin is 0,0
appRect.origin = CGPointMake(0.0f, 0.0f);

// Add the subviews, each stepped by 32 pixels on each side


UIView *subview = [[UIView alloc] initWithFrame:CGRectInset(appRect, 32.0f,
➥32.0f)];
subview.backgroundColor = [UIColor lightGrayColor];
[contentView addSubview:subview];
[subview release];

subview = [[UIView alloc] initWithFrame:CGRectInset(appRect, 64.0f, 64.0f)];


subview.backgroundColor = [UIColor darkGrayColor];
[contentView addSubview:subview];
[subview release];

subview = [[UIView alloc] initWithFrame:CGRectInset(appRect, 96.0f, 96.0f)];


subview.backgroundColor = [UIColor blackColor];
[contentView addSubview:subview];
[subview release];
}

Figure 2-3 The code in Recipe 2-1 defines a UIView controller’s


main view with three colored, nested subviews.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 44

44 Chapter 2 Views

Reorienting
Extending Recipe 2-1 to enable orientation changes takes thought.You cannot just swap
each subview’s heights and widths as you might assume.That’s because the shapes of
horizontal and vertical applications on the iPhone use different aspect ratios. Assuming a
20-pixel status bar, portrait view areas are 320 pixels wide by 460 pixels high; landscapes
are 480 pixels wide by 300 pixels high (refer to Figure 2-2).This difference throws off
interfaces that depend solely on rotation to reorient.
To rotate this example, add code that distinguishes landscape orientations from portrait
ones and adjust the frames accordingly.This is shown in Recipe 2-2.
Avoid reorientation schemes that rely on toggling (for example, “I was just in portrait
mode so, if the orientation changed, I must be in landscape mode.”) It’s entirely possible
to switch from left-landscape to right-landscape without hitting a portrait state in-
between. Orientation is all about sensors and feedback, and the iPhone is not guaranteed
to catch any middle state between two orientations. Fortunately, UIKit provides a
UIViewController callback that alerts you to new orientations and that specifies what
that orientation will be.

Recipe 2-2 Adding Reorientation Support to the Preceding Subview Example


- (void)willRotateToInterfaceOrientation:
(UIInterfaceOrientation)orientation
duration:(NSTimeInterval)duration {

CGRect apprect;
apprect.origin = CGPointMake(0.0f, 0.0f);

// adjust the frame size based on actual orientation


if ((orientation == UIInterfaceOrientationLandscapeLeft) ||
➥(orientation == UIInterfaceOrientationLandscapeRight))
apprect.size = CGSizeMake(480.0f, 300.0f);
else
apprect.size = CGSizeMake(320.0f, 460.0f);

// resize each subview accordingly


float offset = 32.0f;
for (UIView *subview in [contentView subviews]) {
CGRect frame = CGRectInset(apprect, offset, offset);
[subview setFrame:frame];
offset += 32.0f;
}
}

// Allow the view to respond to iPhone Orientation changes


-(BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 45

Recipe: Dragging Views 45

Recipe 2-2 Continued


{
return YES;
}

Recipe: Dragging Views


Cocoa Touch simplifies direct view manipulation.When dealing with many onscreen
views, the iPhone takes charge of deciding which view the user touched and passes any
touch events to the proper view for you.This helps you write concrete direct-manipulation
interfaces where users touch, drag, and interact with onscreen objects.
Recipe 2-3 centers on touches in action.This example creates a child of
UIImageView called DragView that enables users to drag the view around the iPhone
screen. Being an image view, it’s important to enable its user interaction, via [dragger
setUserInteractionEnabled:YES].This holds true for backdrops as well as direct-
interaction views.Whenever working with UIImageView in direct-manipulation interfaces,
make sure to enable interaction, no matter what role in the view hierarchy.With image
views, the user interaction toggle affects all the view’s children as well as the view itself.
When a user first touches any DragView (see the flowers in Figure 2-4), the object
stores the start location as an offset from the view’s origin. As the user drags, the view
moves along with the finger—always maintaining the same origin offset so that the
movement feels natural.

Figure 2-4 The code in Recipe 2-3 creates an interface with


16 flowers that can be dragged around the iPhone screen.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 46

46 Chapter 2 Views

Note
The way the example in Figure 2-4 is built, you can use multiple fingers to drag more than
one flower around the screen at once. It’s not multitouch per se because each flower
(UIView) responds to only one touch at a time. A discussion of true multitouch interaction
follows later in this chapter.

Touching an object also does one more thing in this code: It pops that object to the
front of the parent view.This means any dragged object always floats over any other
object onscreen. Do this by telling the view’s parent (its superview) to bring the view
to its front.

UITouch
The UITouch class defines how fingers move across the iPhone screen.Touches are sent
while invoking the standard began, moved, and ended handlers.You can also query user
events (of the UIEvent class) to return touches affecting a given view through
touchesForView: and touchesForWindow:.These calls return an unordered set
(NSSet) of touches.

Note
Send allObjects to any NSSet to return an array of those objects.

A touch tells you several things: where the touch took place (both the current and
most recent previous location), what stage of the touch was used (essentially mouse
down, mouse moved, mouse up), a tap count (for example, single-tap/double-tap), when
the touch took place (through a time stamp), and so forth.
For nonmultitouch interaction styles, assume that you’re dealing with a single touch
at any time.The code in Recipe 2-3 recovers the first available touch for each event by
calling anyObject on the returned touch set.

Recipe 2-3 Building Multiple Draggable Views


/*
* DragView: Draggable views
*/

@interface DragView : UIImageView


{
CGPoint startLocation;
}
@end

@implementation DragView

// Note the touch point and bring the touched view to the front
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 47

Recipe: Dragging Views 47

Recipe 2-3 Continued


{
CGPoint pt = [[touches anyObject] locationInView:self];
➥startLocation = pt;
[[self superview] bringSubviewToFront:self];
}

// As the user drags, move the flower with the touch


- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
CGPoint pt = [[touches anyObject] locationInView:self];
CGRect frame = [self frame];

frame.origin.x += pt.x - startLocation.x;


frame.origin.y += pt.y - startLocation.y;
[self setFrame:frame];
}
@end

/*
* Hello Controller: The primary view controller
*/

@interface HelloController : UIViewController


{
UIView *contentView;
}
@end

@implementation HelloController

#define MAXFLOWERS 16

CGPoint randomPoint() {return CGPointMake(random() % 256, random() % 396);}

- (void)loadView
{
// Create the main view with a black background
CGRect apprect = [[UIScreen mainScreen] applicationFrame];
contentView = [[UIView alloc] initWithFrame:apprect];
contentView.backgroundColor = [UIColor blackColor];
self.view = contentView;
[contentView release];

// Add the flowers to random points on the screen


for (int i = 0; i < MAXFLOWERS; i++)
{
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 48

48 Chapter 2 Views

Recipe 2-3 Continued


CGRect dragRect = CGRectMake(0.0f, 0.0f, 64.0f, 64.0f);
dragRect.origin = randomPoint();
DragView *dragger = [[DragView alloc] initWithFrame:dragRect];
[dragger setUserInteractionEnabled:YES];

// select random flower color


NSString *whichFlower = [[NSArray arrayWithObjects:@"blueFlower.png",
➥@"pinkFlower.png", @"orangeFlower.png", nil] objectAtIndex:(random() %
➥3)];
[dragger setImage:[UIImage imageNamed:whichFlower]];

// add the new subview


[contentView addSubview:dragger];
[dragger release];
}
}

-(void) dealloc
{
[contentView release];
[super dealloc];
}
@end

Adding Persistence
Persistence represents a key iPhone design touch point. After users leave a program,
Apple strongly recommends that they return to a state that matches as closely to where
they left off as possible. Adding persistence to this sample code involves several steps:
1. Storing the data
2. Resuming from a saved session
3. Providing a startup image that matches the last session

Storing State
Every view knows its position because you can query its frame.This enables you to
recover and store positions for each onscreen flower.The flower type (green, pink, or
blue) is another matter. For each view to report its current flower, the DragView class
must store that value, too. Adding a string instance variable enables the view to return
the image name used. Listing 2-1 shows the extended DragView class definition.

Listing 2-1 The Updated DragView Class Includes a String to Store the Flower Type
@interface DragView : UIImageView
{
CGPoint startLocation;
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 49

Recipe: Dragging Views 49

Listing 2-1 Continued


NSString *whichFlower;
}
@property (nonatomic, retain) NSString *whichFlower;
@end

Adding this extra variable enables the HelloController class to store both a list of
colors and a list of locations to its defaults file. A simple loop collects both values from
each draggable view and then stores them. Listing 2-2 presents an updateDefaults
method, as defined in HelloController.This method saves the current state to disk. It
should be called in the application delegate’s applicationWillTerminate: method,
just before the program ends.
Notice the use here of NSStringFromCGRect(). It provides a tight way to store
frame information as a string.To recover the rectangle, issue CGRectFromString().
Each call takes one argument: a CGRect in the first case, an NSString * in the second.
The UIKit framework provides calls that translate points and sizes as well as rectangles to
and from strings.
Defaults, as you can see, work like a dictionary. Just assign an object to a key and the
iPhone “automagically” updates the preferences file associated with your application ID.
Your application ID is defined in Info.plist. Defaults are stored in Library/Preferences
inside your application’s sandbox. Calling the synchronize function updates those
defaults immediately instead of waiting for the program to terminate.

Listing 2-2 Storing Flower Locations via User Defaults


// Collect all the colors and locations and save them for the next use
- (void) updateDefaults
{
NSMutableArray *colors = [[NSMutableArray alloc] init];
NSMutableArray *locs = [[NSMutableArray alloc] init];

for (DragView *dv in [contentView subviews]) {


[colors addObject:[dv whichFlower]];
[locs addObject:NSStringFromCGRect([dv frame])];
}

[[NSUserDefaults standardUserDefaults] setObject:colors forKey:@"colors"];


[[NSUserDefaults standardUserDefaults] setObject:locs forKey:@"locs"];
[[NSUserDefaults standardUserDefaults] synchronize];
[colors release];
[locs release];
}
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 50

50 Chapter 2 Views

Recovering State
Persistence awareness generally resides in the view controller’s init or loadView (for
example, before the view actually appears).These methods should find any previous state
information and, for this example, match the flowers to that state.When querying user
defaults, this code checks whether state data is unavailable (for example, the value
returned is nil).When state data goes missing, the method creates random flowers at ran-
dom points. Listing 2-3 shows a state-aware version of loadView.

Note
When working with large data sources, you may want to initialize and populate your saved
object array in the UIViewController‘s init method, and then draw them in loadView.
Where possible, use threading when working with many objects to avoid blocking.

Listing 2-3 Checking for Previous State


- (void)loadView
{
// Create the main view
CGRect apprect = [[UIScreen mainScreen] applicationFrame];
contentView = [[UIView alloc] initWithFrame:apprect];
contentView.backgroundColor = [UIColor blackColor];
self.view = contentView;

// Attempt to read in previous colors and locations


NSMutableArray *colors, *locs;
colors = [[NSUserDefaults standardUserDefaults] objectForKey:@"colors"];
locs = [[NSUserDefaults standardUserDefaults] objectForKey:@"locs"];

for (int i = 0; i < MAXFLOWERS; i++)


{
// Use a random point unless there’s a previous location
CGRect dragRect = CGRectMake(0.0f, 0.0f, 64.0f, 64.0f);
dragRect.origin = randomPoint();
if (locs && ([locs count] == MAXFLOWERS))
➥dragRect = CGRectFromString([locs objectAtIndex:i]);
DragView *dragger = [[DragView alloc] initWithFrame:dragRect];
[dragger setUserInteractionEnabled:YES];

// Use a random color unless there’s a previous color


NSString *whichFlower = [[NSArray arrayWithObjects:@"blueFlower.png",
➥@"pinkFlower.png", @"orangeFlower.png", nil] objectAtIndex:(random()
➥% 3)];
if (colors && ([colors count] == MAXFLOWERS))
➥whichFlower = [colors objectAtIndex:i];
[dragger setWhichFlower:whichFlower];
[dragger setImage:[UIImage imageNamed:whichFlower]];
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 51

Recipe: Clipped Views 51

Listing 2-3 Continued


// Add the subview
[contentView addSubview:dragger];
[dragger release];
}

Startup Image
Apple has not yet included persistence screenshot capabilities into its official SDK
release, although the functionality is partially available in the UIKit framework as an
undocumented call.To access the _writeApplicationSnapshot feature shown in
Listing 2-4, you must add it by hand to the UIApplicationClass interface. Once
added, you can build a cached shot of your screen before ending the application.

Note
See Chapter 1, “Introducing the iPhone SDK,” for further discussion about using
undocumented calls and features in your programs.

The idea is this:When you leave the application, you snap a picture of the screen.
Then when your application starts up (presumably returning you to the same state you
left with), the cached image acts as the Default.png image, giving the illusion that you’re
jumping directly back without any startup sequence.
Apple has yet to enable this feature with the iPhone SDK, and at the time of writing,
applications cannot check in to find updated snapshots. Hopefully, Apple will provide
this functionality in a future firmware release.

Listing 2-4 Screenshotting Before Application Termination


@interface UIApplication (Extended)
-(void) _writeApplicationSnapshot;
@end

[[UIApplication sharedApplication] _writeApplicationSnapshot];

Recipe: Clipped Views


When working with direct-manipulation interfaces, it’s unlikely that you’ll want to deal
solely with rectangular views. Soft borders, rounded corners, and other visual enhance-
ments are easily added to UIView instances.
Clipping creates view shapes that fill only part of a view’s frame.You can produce
clipping with Core Graphics using the drawRect: method of a UIView object, just as
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 52

52 Chapter 2 Views

you would on a Macintosh. Core Graphics enables you to build paths from sources
including points, lines, standard shapes (such as ellipses), and Bézier curves. Clipping your
views to these paths creates the illusion of nonrectangular onscreen objects. Figure 2-5
shows a number of onscreen circular clipped views, clearly overlapping with each other.
These views were created by the code shown in Listing 2-5.This code creates a path,
performs the clipping, and then draws into the clipped view.

Figure 2-5 Clipping enables you to create


nonrectangular views onscreen from rectangular source
material, using rectangular UIView frames.

Listing 2-5 Clipping a View to a Circular Path


- (void) drawRect: (CGRect) aRect
{

CGRect bounds = CGRectMake(0.0f, 0.0f, SIDELENGTH, SIDELENGTH);

// Create a new path


CGContextRef context = UIGraphicsGetCurrentContext();
CGMutablePathRef path = CGPathCreateMutable();

// Add circle to path


CGPathAddEllipseInRect(path, NULL, bounds);
CGContextAddPath(context, path);
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 53

Recipe: Clipped Views 53

Listing 2-5 Continued


// Clip to the circle and draw the logo
CGContextClip(context);
[logo drawInRect:bounds];
CFRelease(path);
}

Balancing Touches with Clipping


Visual clipping does not affect how UIViews respond to touches.The iPhone senses user
taps throughout the entire view frame.This includes the undrawn area such as the
corners of the frame outside the actual circles of Figure 2-5 just as much as the clipped
presentation.That means that unless you add some sort of hit test, users may attempt to
tap through to a view that’s “obscured” by the clear portion of the UIView frame.
Listing 2-6 adds a simple hit test to the clipped views, determining whether touches
fall within the clipping path. I implemented circular clipping and circular hit tests to
provide the simplest example. Use any computable test method you like to determine
whether a user touch intersects the view. Add pointInside:withEvent: to your
UIView subclass and return YES when the touch has properly hit your view or NO when
it does not.

Listing 2-6 Checking Circular Views against Touches


- (BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
CGPoint pt;
float HALFSIDE = SIDELENGTH / 2.0f;

// normalize with centered origin


pt.x = (point.x - HALFSIDE) / HALFSIDE;
pt.y = (point.y - HALFSIDE) / HALFSIDE;

// x^2 + y^2 = hypoteneus length


float xsquared = pt.x * pt.x;
float ysquared = pt.y * pt.y;

// If the length < 1, the point is within the clipped circle


if ((xsquared + ysquared) < 1.0) return YES;
return NO;
}
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 54

54 Chapter 2 Views

Accessing Pixel-by-Pixel Values


There are many ways to test user touches against views. Listing 2-6 computed whether a
touch fell within a circle’s radius.With hit masks and variable transparency images, you
can test against a point’s alpha value.Translucency controls whether you trigger a
response. Listing 2-7 extends the UIImageView class to add an image’s bitmap represen-
tation. It tests touches against alpha values in the bitmap, point by point. Pixels whose
alpha levels fall below 0.5 will not respond to touches using this code.

Note
The code in this listing returns a bitmap context, and its bitmap data is based on Apple
sample code.

Listing 2-7 Testing Touch Hits Against a Bitmap


// Return a bitmap context using alpha/red/green/blue byte values
CGContextRef CreateARGBBitmapContext (CGImageRef inImage)
{
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;

size_t pixelsWide = CGImageGetWidth(inImage);


size_t pixelsHigh = CGImageGetHeight(inImage);
bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
colorSpace = CGColorSpaceCreateDeviceRGB();

if (colorSpace == NULL)
{
fprintf(stderr, "Error allocating color space\n");
return NULL;
}

// allocate the bitmap & create context


bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
{
fprintf (stderr, "Memory not allocated!");
CGColorSpaceRelease( colorSpace );
return NULL;
}
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 55

Recipe: Clipped Views 55

Listing 2-7 Continued


context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8,
➥bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedFirst);
if (context == NULL)
{
free (bitmapData);
fprintf (stderr, "Context not created!");
}
CGColorSpaceRelease( colorSpace );
return context;
}

// Return Image Pixel data as an ARGB bitmap


unsigned char *RequestImagePixelData(UIImage *inImage)
{
CGImageRef img = [inImage CGImage];
CGSize size = [inImage size];

CGContextRef cgctx = CreateARGBBitmapContext(img, size);


if (cgctx == NULL) return NULL;

CGRect rect = {{0,0},{size.width, size.height}};


CGContextDrawImage(cgctx, rect, img);
unsigned char *data = CGBitmapContextGetData (cgctx);
CGContextRelease(cgctx);

return data;
}

// Create an Image View that stores a copy of its image as an addressable bitmap
@interface BitMapView : UIImageView
{
unsigned char *bitmap;
CGSize size;
UIView *colorView;
}
@end
@implementation BitMapView

// Hit test relies on the alpha level of the touched pixel


- (BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
long startByte = (int)((point.y * size.width) + point.x) * 4;
int alpha = (unsigned char) bitmap[startByte];
return (alpha > 0.5);
}
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 56

56 Chapter 2 Views

Listing 2-7 Continued


-(void) setImage:(UIImage *) anImage
{
[super setImage:anImage];
bitmap = RequestImagePixelData(anImage);
size = [anImage size];
}
@end

Recipe: Detecting Multitouch


By enabling multitouch interaction in your UIViews, the iPhone enables you to recover
and respond to multifinger interaction.This recipe, shown in Recipe 2-4, demonstrates
how to add multitouch to your iPhone applications.
To begin, set multipleTouchEnabled to YES or override
isMultipleTouchEnabled for your view.This tells your application to poll for more
than one UITouch at a time. Now when you call touchesForView:, the returned set
may contain several touches. Use NSSet’s allObjects method to convert that set into
an addressable NSArray.When the array’s count exceeds one, you know you’re dealing
with multitouch.
In theory, the iPhone could support an arbitrary number of touches. In practice, multi-
touch is limited to five finger touches at a time. Even five at a time goes beyond what
most developers need.There aren’t many meaningful gestures you can make with five
fingers at once.This particularly holds true when you grasp the iPhone with one hand
and touch with the other. Perhaps it’s a comfort to know that if you need to, the extra
finger support has been built in. Unfortunately, when you are using three or more touches
at a time, the screen has a tendency to lose track of one or more of those fingers. It’s hard
to programmatically track smooth gestures when you go beyond two finger touches.
Touches are not grouped. If, for example, you touch the screen with two fingers from
each hand, there’s no way to determine which touches belong to which hand.The touch
order is arbitrary. Although grouped touches retain the same finger order for the lifetime
of a single touch event (down, move, up), the order may change the next time your user
touches the screen.When you need to distinguish touches from each other, build a touch
dictionary indexed by the touch objects.

Note
The drawRect: routine in Recipe 2-4 clears its context each time it is called. This
removes previous circles and lines from the display. Comment out this line if you want to
see an event trail.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 57

Recipe: Detecting Multitouch 57

Figure 2-6 The iPhone enables you to capture


multitouch events as well as single-touch ones.
In this example, two circles mark the points at
which the user has touched the screen.

Recipe 2-4 Visualizing Multitouch


@interface MultiTouchView : UIView
{
CGPoint loc1, loc2;
}
@property (nonatomic) CGPoint loc1;
@property (nonatomic) CGPoint loc2;
@end

@implementation MultiTouchView
@synthesize loc1;
@synthesize loc2;

- (BOOL) isMultipleTouchEnabled {return YES;}

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event


{
NSArray *allTouches = [touches allObjects];
int count = [allTouches count];
if (count > 0) loc1 = [[allTouches objectAtIndex:0] locationInView:self];
if (count > 1) loc2 = [[allTouches objectAtIndex:1] locationInView:self];
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 58

58 Chapter 2 Views

Recipe 2-4 Continued


[self setNeedsDisplay];
}

// React to moved touches the same as to "began"


- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
[self touchesBegan:touches withEvent:event];
}

- (void) drawRect: (CGRect) aRect


{
// Get the current context
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, aRect);

// Set up the stroke and fill characteristics


CGContextSetLineWidth(context, 3.0f);
CGFloat gray[4] = {0.5f, 0.5f, 0.5f, 1.0f};
CGContextSetStrokeColor(context, gray);
CGFloat red[4] = {0.75f, 0.25f, 0.25f, 1.0f};
CGContextSetFillColor(context, red);

// Draw a line between the two location points


CGContextMoveToPoint(context, loc1.x, loc1.y);
CGContextAddLineToPoint(context, loc2.x, loc2.y);
CGContextStrokePath(context);

CGRect p1box = CGRectMake(loc1.x, loc1.y, 0.0f, 0.0f);


CGRect p2box = CGRectMake(loc2.x, loc2.y, 0.0f, 0.0f);
float offset = -8.0f;

// circle point 1
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectInset(p1box, offset, offset));
CGContextAddPath(context, path);
CGContextFillPath(context);
CFRelease(path);

// circle point 2
path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectInset(p2box, offset, offset));
CGContextAddPath(context, path);
CGContextFillPath(context);
CFRelease(path);
}
@end
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 59

UIView Animations 59

Note
Apple provides many Core Graphics/Quartz 2D resources on its developer Web site.
Although these forums, mailing lists, and source code samples are not iPhone specific,
they offer an invaluable resource for expanding your iPhone Core Graphics knowledge.

UIView Animations
UIView animation provides one of the odd but lovely perks of working with the iPhone
as a development platform. It enables you to slow down changes when updating views,
producing smooth animated results that enhance the user experience. Best of all, this all
occurs without you having to do much work.
UIView animations are perfect for building a visual bridge between a view’s current
and changed states.With them, you emphasize visual change and create an animation
that links those changes together. Animatable changes include the following:
n Changes in location—moving a view around the screen
n Changes in size—updating the view’s frame
n Changes in transparency—altering the view’s alpha value
n Changes in rotation or any other affine transforms that you apply to a view

Building UIView Animation Blocks


UIView animations work as blocks, a complete transaction that progresses at once. Start
the block by issuing beginAnimations:context:. End the block with
commitAnimations.These class methods are sent to UIView and not to individual
views. In the block between these two calls, you define the way the animation works and
perform the actual view updates.The animation controls you’ll use are as follows:
n beginAnimations:context. Marks the start of the animation block.
n setAnimationCurve. Defines the way the animation accelerates and decelerates.
Use ease-in/ease-out (UIViewAnimationCurveEaseInOut) unless you have
some compelling reason to select another curve.The other curve types are ease in
(accelerate into the animation), linear (no animation acceleration), and ease out
(accelerate out of the animation). Ease-in/ease-out provides the most natural-
feeling animation style.
n setAnimationDuration. Specifies the length of the animation, in seconds.This
is really the cool bit.You can stretch out the animation for as long as you need it
to run. Be aware of straining your user’s patience and keep your animations below
a second or two in length.
n commitAnimations. Marks the end of the animation block.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 60

60 Chapter 2 Views

Sandwich your actual view change commands after setting up the animation details
and before ending the animation. Listing 2-8 shows UIView animations in action by set-
ting an animation curve and the animation duration (here, one second).The actual
change being animated is a transparency update.The alpha value of the content view
goes to zero, making it invisible. Instead of the view simply disappearing, this animation
block slows down the change and fades it out of sight.

Note
Apple often uses two animation blocks one after another to add bounce to their anima-
tions. For example, they might zoom into a view a bit more than needed and then use a
second animation to bring that enlarged view down to its final size. Use “bounces” to add
a little more life to your animation blocks. Be sure that the animations do not overlap.
Either add a delay so that the second animation does not start until the first ends
(performSelector: withObject: afterDelay:) or assign an animation delegate
callback (animationDidStop: finished:) to catch the end of the first animation and
start the second.

Listing 2-8 Using UIView Animation Calls


[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:1.0];
[contentView setAlpha:0.0f];
[UIView commitAnimations];

Recipe: Fading a View In and Out


There are times you’ll want to add information to your screen that overlays your view
but does not of itself do anything. For example, you might show a top scores list or some
instructions or provide a context-sensitive tool tip. Recipe 2-5 demonstrates how to use
a UIView animation block to slowly fade a noninteractive overlay view into and out of
sight.
This is done by creating a custom ToggleView. As defined by this code,
ToggleViews are UIViews with one child, an image view.When tapped, the animation
block toggles the alpha setting from off to on or on to off.The key bits for making this
happen well and reliably are as follows:
n Make sure the child does not look for interaction events. Cocoa Touch does not
allow transparent views to catch touches. So you must allow the parent, the
ToggleView, to handle all user interactions instead.When creating the child, the
method sets the child’s property userInteractionEnabled to NO.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 61

Recipe: Fading a View In and Out 61

n Make sure to catch only mouse down events. For simple on-off-on-off toggles,
catch and respond only to presses for the most natural user feedback. Otherwise,
user taps will hide and then immediately show your image view again.
n Pick a reasonable animation time. If you lengthen the animation beyond what your
user is willing to handle, you’ll end up handling new taps before the first anima-
tion has completed.The one-second animation shown here is just about the
longest time you’ll want to use. Half- or quarter-second animations are better for
common interface changes.

Recipe 2-5 Using UIView Animations with Transparency Changes


@interface ToggleView: UIView
{
BOOL isVisible;
UIImageView *imgView;
}
@end

@implementation ToggleView
- (id) initWithFrame: (CGRect) aFrame;
{
self = [super initWithFrame:aFrame];
isVisible = YES;
imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
➥applicationFrame]];
[imgView setImage:[UIImage imageNamed:@"alphablend.png"]];
imgView.userInteractionEnabled = NO;
[self addSubview:imgView];
[imgView release];
return self;
}

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event


{
// only respond to mouse down events
UITouch *touch = [touches anyObject];
if ([touch phase] != UITouchPhaseBegan) return;

isVisible = !isVisible;

CGContextRef context = UIGraphicsGetCurrentContext();


[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:1.0];
[imgView setAlpha:(float)isVisible];
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 62

62 Chapter 2 Views

Recipe 2-5 Continued


[UIView commitAnimations];
}
- (void) dealloc
{
[imgView release];
[super dealloc];
}
@end

Recipe: Swapping Views


The UIView animation block doesn’t limit you to a single change. Recipe 2-6 combines
frame size updates with transparency changes to create a more compelling animation.
You do this by adding several directives at once to the animation block. Recipe 2-6 per-
forms four actions at a time. It zooms and fades one view into place, while zooming out
and fading away another. Figure 2-7 provides a preview of this animation in action.

Figure 2-7 Issuing several view changes


within a single UIView animation block can
create complex visual effects.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 63

Recipe: Swapping Views 63

Recipe 2-6 Combining Multiple View Changes in Animation Blocks


@interface ToggleView: UIView
{
BOOL isOne;
UIImageView *imgView1, *imgView2;
}
@end

@implementation ToggleView

#define BIGRECT CGRectMake(0.0f, 0.0f, 320.0f, 435.0f)


#define SMALLRECT CGRectMake(130.0f, 187.0f, 60.0f, 60.0f)

- (id) initWithFrame: (CGRect) aFrame;


{
self = [super initWithFrame:aFrame];

// Load both views, make them noninteractive


imgView1 = [[UIImageView alloc] initWithFrame:BIGRECT];
imgView2 = [[UIImageView alloc] initWithFrame:SMALLRECT];
[imgView1 setImage:[UIImage imageNamed:@"one.png"]];
[imgView2 setImage:[UIImage imageNamed:@"two.png"]];
imgView1.userInteractionEnabled = NO;
imgView2.userInteractionEnabled = NO;

// image 1 is in front of image 2 to begin


[self addSubview:imgView2];
[self addSubview:imgView1];
isOne = YES;
[imgView1 release];
[imgView2 release];
return self;
}
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
// Determine which view occupies which role
UIImageView *big = isOne ? imgView1 : imgView2;
UIImageView *little = isOne ? imgView2 : imgView1;
isOne = !isOne;

// Pack all the changes into the animation block


CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:1.0];

[big setFrame:SMALLRECT];
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 64

64 Chapter 2 Views

Recipe 2-6 Continued


[big setAlpha:0.5];
[little setFrame:BIGRECT];
[little setAlpha:1.0];

[UIView commitAnimations];

// Hide the shrunken "big" image.


[big setAlpha:0.0f];
[[big superview] bringSubviewToFront:big];
}
-(void) dealloc
{
[imgView1 release];
[imgView2 release];
[super dealloc];
}
@end

Recipe: Flipping Views


Transitions enable you to extend your UIView animation blocks to add even more
visual flair.Two transitions—UIViewAnimationTransitionFlipFromLeft and
UIViewAnimationTransitionFlipFromRight—enable you to do just what their
names suggest. At this time, you can flip views left or flip views right.These are the only
two official transitions available for UIViews.

Note
During the SDK beta period, Apple promised additional animations that were never
realized, specifically UIViewAnimationTransitionCurlUp and
UIViewAnimationTransitionCurlDown. These extra animations may appear at some
future time.

To use transitions in UIView animation blocks, you need to do two things. First, you
must add the transition as a block parameter. Use setAnimationTransition: to assign
the transition to the enclosing UIView animation block. Second, you should rearrange
the view order while inside the block.This is best done with
exchangeSubviewAtIndex: withSubviewAtIndex:. Recipe 2-7 demonstrates how
to create a simple flip view using these techniques.When tapped, the views use the ani-
mation to flip from one side to the next, as shown in Figure 2-8.
Do not confuse the UIView animation blocks with the Core Animation
CATransition class. Unfortunately, you cannot assign a CATransition to your UIView
animation.To use a CATransition, you must apply it to a UIView’s layer, which is
shown in the next recipe.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 65

Recipe: Flipping Views 65

Figure 2-8 Use UIView’s built-in


transition animations to flip your
way from one view to the next.

Recipe 2-7 Using Transitions with UIView Animation Blocks


@interface FlipView : UIImageView
@end

@implementation FlipView
- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
// Start Animation Block
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromLeft
➥forView:[self superview] cache:YES];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:1.0];

// Animations
[[self superview] exchangeSubviewAtIndex:0 withSubviewAtIndex:1];

// Commit Animation Block


[UIView commitAnimations];
}
@end
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 66

66 Chapter 2 Views

Recipe: Applying CATransitions to Layers


Core Animation Transitions expand your UIView animation vocabulary with just a few
small differences in implementation. CATransitions work on layers rather than on
views. Layers are the Core Animation rendering surfaces associated with each UIView.
When working with Core Animation, you apply CATransitions to a view’s default
layer ([myView layer]) rather than the view itself.
You don’t set your parameters through UIView the way you do with UIView animation.
You create a Core Animation object, set its parameters, and then add the parameterized
transition to the layer. Listing 2-9 shows a simple pushFromLeft method that you might
swap out for the flip method shown in Recipe 2-7.
Animations use both a type and a subtype. The type specifies the kind of transition
used.The subtype sets its direction.Together the type and subtype tell how the views
should act when you apply the animation to them.
Core Animation Transitions are distinct from the two UIView flips discussed in the
previous recipe. Cocoa Touch offers four types of Core Animation.These available types
include cross fades, pushes (used in Listing 2-9), reveals (where one view slides off another),
and covers (where one view slides onto another).The last three types enable you to
specify the direction of motion for the transition through subtypes. For obvious reasons,
cross fades do not have a direction and they do not use subtypes.
Core Animation is part of the Quartz Core framework.To use this sample code, you
must add the Quartz Core framework to your project and import <QuartzCore/
QuartzCore.h> into your code.

Note
Apple’s Core Animation features 2D and 3D routines built around Objective-C classes.
These classes provide graphics rendering and animation for your iPhone and Macintosh
applications. Core Animation avoids many low-level development details associated with,
for example, direct OpenGL while retaining the simplicity of working with hierarchical views.

Listing 2-9 Adding a Core Animation Transition to a UIView Layer


@implementation PushView
- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{

CATransition *animation = [CATransition animation];


[animation setDelegate:self];
[animation setDuration:1.0f];
[animation setTimingFunction:UIViewAnimationCurveEaseInOut];
[animation setType: kCATransitionPush];
[animation setSubtype: kCATransitionFromLeft];

[[self superview] exchangeSubviewAtIndex:0 withSubviewAtIndex:1];


02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 67

Recipe: Applying CATransitions to Layers 67

Listing 2-9 Continued


[[[self superview] layer] addAnimation:animation
➥forKey:@"transitionViewAnimation"];
}
@end

Undocumented Animation Types


The iPhone actually implements more animation types than official documents would
suggest. As Listing 2-10 shows, the iPhone is perfectly capable of handling map curls à la
the Google Maps application.This code, which works on the iPhone but not the
Simulator, relies on extracting animation names from the UIKit binary framework file.
Like all undocumented calls, this is not without risk. Apple may change or delete
these animations at any time. Other animation types include pageCurl, pageUnCurl,
suckEffect, spewEffect, cameraIris (from the Photos application),
cameraIrisHollowOpen, cameraIrisHollowClose, genieEffect (typically used
for deleting garbage), unGenieEffect, rippleEffect, twist, tubey, swirl,
charminUltra, zoomyIn, zoomyOut, and oglFlip.
Note the use of setRemovedOnCompletion: NO.This freezes the animation at its
end, allowing the curled map to remain visible, as shown in Figure 2-9.

Figure 2-9 This eye-catching effect uses an


undocumented Core Animation type called mapCurl.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 68

68 Chapter 2 Views

Listing 2-10 Calling Undocumented Animation Types


- (void) performCurl
{
// Curl the image up or down
CATransition *animation = [CATransition animation];
[animation setDelegate:self];
[animation setDuration:1.0f];
[animation setTimingFunction:UIViewAnimationCurveEaseInOut];
[animation setType:(notCurled ? @"mapCurl" : @"mapUnCurl")];
[animation setRemovedOnCompletion:NO];
[animation setFillMode: @"extended"];
[animation setRemovedOnCompletion: NO];
notCurled = !notCurled;

[[topView layer] addAnimation:animation forKey:@"pageFlipAnimation"];


}

General Core Animation Calls


The iPhone provides partial support for Core Animation calls. By partial, I mean that
many standard classes are missing in action. CIFilter is one such class. It’s not included
in Cocoa Touch, although the CALayer and CATransition classes are both filter-aware.
If you’re willing to work through these limits, you can freely use standard Core
Animation calls in your programs.
Listing 2-11 shows iPhone native Core Animation code based on a sample from
Lucas Newman (http://lucasnewman.com).When run, this method scales down and
fades away the contents of a UIImageView.The source adds a translucent reflection layer,
which follows the view.
This code remains virtually unchanged from the Mac OS X sample it was based on.
More complex Core Animation samples may offer porting challenges, but for simple
reflections, shadows, and transforms, all the functionality you need can be had at the
native iPhone level.

Listing 2-11 Native iPhone Core Animation Calls


// Adapted from http://lucasnewman.com/animationsamples.zip
- (void) scaleAndFade
{
// create the reflection layer
CALayer *reflectionLayer = [CALayer layer];

// share the contents image with the screen layer


reflectionLayer.contents = [contentView layer].contents;
reflectionLayer.opacity = 0.4;
reflectionLayer.frame = CGRectOffset([contentView layer].frame, 0.5,
➥416.0f + 0.5);
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 69

Recipe: Swiping Views 69

Listing 2-11 Continued


// flip the y-axis
reflectionLayer.transform = CATransform3DMakeScale(1.0, -1.0, 1.0);
reflectionLayer.sublayerTransform = reflectionLayer.transform;
[[contentView layer] addSublayer:reflectionLayer];

#define ANIMATION_DURATION (4.0)

[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:ANIMATION_DURATION]
➥forKey:kCATransactionAnimationDuration];

// scale it down
CABasicAnimation *shrinkAnimation = [CABasicAnimation
➥animationWithKeyPath:@"transform.scale"];
shrinkAnimation.timingFunction = [CAMediaTimingFunction
➥functionWithName:kCAMediaTimingFunctionEaseIn];
shrinkAnimation.toValue = [NSNumber numberWithFloat:0.0];
[[contentView layer] addAnimation:shrinkAnimation forKey:@"shrinkAnimation"];

// fade it out
CABasicAnimation *fadeAnimation = [CABasicAnimation
➥animationWithKeyPath:@"opacity"];
fadeAnimation.toValue = [NSNumber numberWithFloat:0.0];
fadeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:
➥kCAMediaTimingFunctionEaseIn];
[[contentView layer] addAnimation:fadeAnimation forKey:@"fadeAnimation"];

[CATransaction commit];
}

Recipe: Swiping Views


Swipes are a convenient but often-overlooked iPhone interaction style.When a user
quickly drags his or her finger across the screen, the UITouch objects returned for that
gesture include an info property.This property defines the direction in which the user
swiped the screen, (for example, up, down, left, or right).This behavior is best seen in the
iPhone’s Photos application, when users swipe left or right to move between album
pictures.
Early versions of the iPhone SDK offered swipe detection as a standard part of the
UITouch object, but later releases dropped that capability. Instead, Apple offered
workaround code in its iPhone Developers Guide. Recipe 2-8 is based on that code. It
ensures that a user continues finger movement in one direction by defining a safety zone
around the movement. If the user strays diagonally more than 6 pixels off course, the
swipe cancels. Stay on-course for at least 12 pixels and the swipe is set.
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 70

70 Chapter 2 Views

Recipe 2-8 applies a Core Animation Transition on completion of a successful swipe.


It uses the swipe direction to set the animation’s subtype. Subtypes are used in Core
Animation to specify the overall movement of the animation, whether up, down, or
sideways.
This sample mimics the interaction style used for browsing through album pictures in
Photos but allows you to move up and down as well as left and right. If you comment
out the kCATransitionPush animation type and replace it with the undocumented
oglFlip in the line that immediately follows it, you’ll receive an even nicer surprise. Far
from being limited to the two core flip directions, the iPhone actually supports a full
four-way flip style, albeit one that Apple has not included in its public SDK.

Note
In early releases of the iPhone SDK, swipes didn’t work in the Simulator. In later versions,
they did. Should you encounter platform limitations while developing (for example, when
working with the Camera), you can easily add workarounds based on testing the platform.
Add compiler directives such as #if defined(TARGET_IPHONE_SIMULATOR) to your
source.

Recipe 2-8 Detecting and Responding to User Swipes in Your Views


- (CATransition *) getAnimation:(NSString *) direction
{
CATransition *animation = [CATransition animation];
[animation setDelegate:self];
[animation setType:kCATransitionPush];
// [animation setType:@"oglFlip"];
[animation setSubtype:direction];
[animation setDuration:1.0f];
[animation setTimingFunction:[CAMediaTimingFunction
➥functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
return animation;
}

#define HORIZ_SWIPE_DRAG_MIN 12
#define VERT_SWIPE_DRAG_MAX 4

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event


{
UITouch *touch = [touches anyObject];
startTouchPosition = [touch locationInView:self];
dirString = NULL;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event


{
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 71

Recipe: Swiping Views 71

Recipe 2-8 Continued


UITouch *touch = touches.anyObject;
CGPoint currentTouchPosition = [touch locationInView:self];

if (fabsf(startTouchPosition.x - currentTouchPosition.x) >=


HORIZ_SWIPE_DRAG_MIN &&
fabsf(startTouchPosition.y - currentTouchPosition.y) <=
VERT_SWIPE_DRAG_MAX)
{
// Horizontal Swipe
if (startTouchPosition.x < currentTouchPosition.x) {
dirString = kCATransitionFromLeft;
}
else
dirString = kCATransitionFromRight;
}
else if (fabsf(startTouchPosition.y - currentTouchPosition.y) >=
HORIZ_SWIPE_DRAG_MIN &&
fabsf(startTouchPosition.x - currentTouchPosition.x) <=
VERT_SWIPE_DRAG_MAX)
{
// Vertical Swipe
if (startTouchPosition.y < currentTouchPosition.y)
dirString = kCATransitionFromBottom;
else
dirString = kCATransitionFromTop;
} else
{
// Process a non-swipe event.
// dirString = NULL;
}
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event


{
if (dirString)
{
CATransition *animation = [self getAnimation:dirString];
[[self superview] exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
[[[self superview] layer] addAnimation:animation forKey:kAnimationKey];

}
}
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 72

72 Chapter 2 Views

Recipe: Transforming Views


Affine transforms enable you to change an object’s geometry by mapping that object
from one view coordinate system into another.The iPhone SDK fully supports standard
affine 2D transforms.With them, you can scale, translate, rotate, and skew your views
however your heart desires and your application demands.
Transforms are defined in Core Graphics, and consist of calls such as
CGAffineTransformMakeRotation and CGAffineTransformScale.These build and
modify the 3-by-3 transform matrices. Once built, use UIView‘s setTransform: call to
apply 2D affine transformations to UIView objects.
Recipe 2-9 demonstrates how to build and apply an affine transform of a UIView.To
create the sample, I kept things simple. I build an NSTimer that ticks every 1/30th of a
second. On ticking, it rotates a view by 1% of pi and scales over a cosine curve. I use the
cosine’s absolute value for two reasons. It keeps the view visible at all times, and it pro-
vides a nice bounce effect when the scaling changes direction.This produces a rotating
and undamped bounce animation.
This is one of those samples that it’s best to build and view as you read through the
code.You’ll be better able to see how the handleTimer: method correlates to the visu-
al effects you’re looking at.

Recipe 2-9 Example of an Affine Transform of a UIView


#import "math.h"
#define PI 3.14159265

@interface HelloController : UIViewController


{
UIView *contentView;
UIImageView *rotateView;
int theta;
}
@end

@implementation HelloController
- (id)init
{
if (self = [super init]) self.title = @"Affine Demo";
return self;
}

- (void) handleTimer: (NSTimer *) timer


{
// Rotate each iteration by 1% of PI
float angle = theta * (PI / 100);
CGAffineTransform transform = CGAffineTransformMakeRotation(angle);
theta = (theta + 1) % 200;
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 73

Recipe: Transforming Views 73

Recipe 2-9 Continued


// For fun, scale by the absolute value of the cosine
float degree = cos(angle);
if (degree < 0.0) degree *= -1.0f;
degree += 0.5f;
CGAffineTransform scaled = CGAffineTransformScale(transform, degree, degree);

// Apply the affine transform


[rotateView setTransform:scaled];
}

- (void)loadView
{
theta = 0;

contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen]


➥applicationFrame]];
rotateView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 240.0f,
➥240.0f)];
[rotateView setImage:[UIImage imageNamed:@"rotateart.png"]];
[rotateView setCenter:CGPointMake(160.0f, 208.0f)];
[contentView addSubview:rotateView];
[rotateView release];

self.view = contentView;
[contentView release];

[NSTimer scheduledTimerWithTimeInterval: 0.03f target: self selector:


➥@selector(handleTimer:)
userInfo: nil repeats: YES];
}

// Allow the view to respond to iPhone Orientation changes


-
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)
interfaceOrientation
{
return NO;
}
-(void) dealloc
{
[contentView release];
[rotateView release];
[super dealloc];
}
@end
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 74

74 Chapter 2 Views

Centering Landscape Views


Use the same affine transform approach to center landscape-oriented views. Listing 2-12
creates a 480-by-320 pixel view, centers it at [160, 240] (using portrait view coordinates),
and then rotates it into place. Half of pi corresponds to 90 degrees, creating a landscape-
right rotation. Centering keeps the entire view onscreen. All subviews, including text
fields, labels, switches, and so on rotate into place along with the parent view.
If you want to work with a landscape keyboard for this view, make sure to call
[[UIApplication sharedApplication] setStatusBarOrientation:
UIInterfaceOrientationLandscapeRight].This sets the status bar orientation,
which controls the keyboard regardless of whether the status bar is hidden or shown.

Listing 2-12 Rotating Landscape Views into Place


@implementation HelloController
- (void)loadView
{
contentView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 480.0f,
➥320.0f)];
[contentView setCenter:CGPointMake(160.0f, 240.0f)];
[contentView setBackgroundColor:[UIColor blackColor]];
[contentView setTransform:CGAffineTransformMakeRotation(3.141592f / 2.0f)];
self.view = contentView;
[contentView release];
}

-(void) dealloc
{
[contentView release];
[super dealloc];
}
@end

Summary
UIViews provide the onscreen components your users see and interact with. As this
chapter has shown, even in their most basic form, they offer incredible flexibility and
power.You’ve discovered how to use views to build up elements on a screen, create
multiple interaction objects, and introduce eye-catching animation. Here’s a collection of
thoughts about the recipes you’ve seen in this chapter that you might want to ponder
before moving on:
n When dealing with multiple onscreen views, hierarchy should always remain front-
most in your mind—no pun! Use your view hierarchy vocabulary
(bringSubviewToFront:, sendSubviewToBack:,
02_0321555457_ch02.qxd 10/2/08 8:25 AM Page 75

Summary 75

exchangeSubviewAtIndex:withSubviewAtIndex:) to take charge of your


views and always present the proper visual context to your users.
n You’re not limited to rectangles. Use UIView / Core Graphics clipping to create
compelling interaction objects that don’t necessarily have right corners.
n Be concrete.The iPhone has a perfectly good touch screen.Why not let your users
drag items around the screen with their fingers? It adds to the reality and the plat-
form’s interactive nature.
n Animate everything. Animations don’t have to be loud, splashy, or bad design.The
iPhone’s strong animation support enables you to add smooth transitions between
user tasks. Short, smooth, focused changes are the iPhone’s bread and butter.
n Users typically have five fingers per hand. Don’t limit yourself to a one-finger
interface when it makes sense to expand your interaction into multitouch territory.
n A solid grounding in Quartz graphics and Core Animation will be your friend.
Using drawRect:, you can build any kind of custom UIView presentation you’d
like, including text, Bézier curves, scribbles, and so forth.
n Explore! This chapter has only touched lightly on the ways you can use UIViews
in your applications. Use this material as a jumping-off point to explore the full
vocabulary of the UIView class.
Google
Bookmarks Delicious Digg Facebook StumbleUpon Reddit Twitter

Java_Rock_Star_CH_Openers.indd 9 6/18/09 1:54:53 PM


Andrew Hunt
David Thomas

The Pragmatic Programmer


Straight from the programming trenches, The Pragmatic Programmer cuts through
the increasing specialization and technicalities of modern software development to
examine the core process--taking a requirement and producing working, maintainable
code that delights its users. It covers topics ranging from personal responsibility and AVAILABLE
career development to architectural techniques for keeping your code flexible and easy • BOOK: 9780201616224
to adapt and reuse. Read this book, and you’ll learn how to • SAFARI ONLINE

• Fight software rot


• Avoid the trap of duplicating knowledge
• Write flexible, dynamic, and adaptable code About the Authors
• Avoid programming by coincidence
• Bullet-proof your code with contracts, assertions, and exceptions Andy Hunt is an avid woodworker
• Capture real requirements and musician, but, curiously, he is
• Test ruthlessly and effectively more in demand as a consultant. He
• Delight your users has worked in telecommunications,
• Build teams of pragmatic programmers banking, financial services, and utili-
• Make your developments more precise with automation ties, as well as in more exotic fields,
such as medical imaging, graphic
Written as a series of self-contained sections and filled with entertaining anecdotes, arts, and Internet services. Andy
thoughtful examples, and interesting analogies, The Pragmatic Programmer specializes in blending tried-and-
illustrates the best practices and major pitfalls of many different aspects of software true techniques with leading-edge
development. Whether you’re a new coder, an experienced programmer, or a manager technologies, creating novel--but
responsible for software projects, use these lessons daily, and you’ll quickly see practical--solutions. Andy owns his
improvements in personal productivity, accuracy, and job satisfaction. You’ll learn skills own consulting business in Raleigh,
and develop habits and attitudes that form the foundation for long-term success in your North Carolina.
career. You’ll become a Pragmatic Programmer.
Dave Thomas likes to fly single-
engine airplanes and pays for his
habit by finding elegant solutions
to difficult problems, consulting
in areas as diverse as aerospace,
banking, financial services, telecom-
munications, travel and transport,
and the Internet. Before moving to
the United States in 1994, Dave
founded an ISO9001-certified
English software company that deliv-
ered sophisticated, custom software
projects throughout the world. Dave
is now an independent consultant
informit.com/aw based in Dallas, Texas.

Java_Rock_Star_CH_Openers.indd 10 6/18/09 1:54:54 PM


The Pragmatic Programmer
2001/2/27 — Page 1 (tmp/pragmatic_thinking)
Copyright 2001 Addison Wesley Longman, Inc

Chapter 1

A Pragmatic Philosophy
What distinguishes Pragmatic Programmers? We feel it’s an attitude, a
style, a philosophy of approaching problems and their solutions. They
think beyond the immediate problem, always trying to place it in its
larger context, always trying to be aware of the bigger picture. After all,
without this larger context, how can you be pragmatic? How can you
make intelligent compromises and informed decisions?

Another key to their success is that they take responsibility for every-
thing they do, which we discuss in The Cat Ate My Source Code. Being
responsible, Pragmatic Programmers won’t sit idly by and watch their
projects fall apart through neglect. In Software Entropy, we tell you how
to keep your projects pristine.

Most people find change difficult to accept, sometimes for good reasons,
sometimes because of plain old inertia. In Stone Soup and Boiled Frogs,
we look at a strategy for instigating change and (in the interests of
balance) present the cautionary tale of an amphibian that ignored the
dangers of gradual change.

One of the benefits of understanding the context in which you work


is that it becomes easier to know just how good your software has to
be. Sometimes near-perfection is the only option, but often there are
trade-offs involved. We explore this in Good-Enough Software.

Of course, you need to have a broad base of knowledge and experience


to pull all of this off. Learning is a continuous and ongoing process.
In Your Knowledge Portfolio, we discuss some strategies for keeping the
momentum up.

1
The Pragmatic Programmer
2001/2/27 — Page 2 (tmp/responsibility)
Copyright 2001 Addison Wesley Longman, Inc

2 C HAPTER 1 A P RAGMATIC P HILOSOPHY

Finally, none of us works in a vacuum. We all spend a large amount


of time interacting with others. Communicate! lists ways we can do this
better.

Pragmatic programming stems from a philosophy of pragmatic think-


ing. This chapter sets the basis for that philosophy.

1 The Cat Ate My Source Code


The greatest of all weaknesses is the fear of appearing weak.
J. B. Bossuet, Politics from Holy Writ, 1709

One of the cornerstones of the pragmatic philosophy is the idea of tak-


ing responsibility for yourself and your actions in terms of your career
advancement, your project, and your day-to-day work. A Pragmatic Pro-
grammer takes charge of his or her own career, and isn’t afraid to admit
ignorance or error. It’s not the most pleasant aspect of programming,
to be sure, but it will happen—even on the best of projects. Despite
thorough testing, good documentation, and solid automation, things
go wrong. Deliveries are late. Unforeseen technical problems come up.

These things happen, and we try to deal with them as professionally as


we can. This means being honest and direct. We can be proud of our
abilities, but we must be honest about our shortcomings—our igno-
rance as well as our mistakes.

Take Responsibility
Responsibility is something you actively agree to. You make a commit-
ment to ensure that something is done right, but you don’t necessarily
have direct control over every aspect of it. In addition to doing your own
personal best, you must analyze the situation for risks that are beyond
your control. You have the right not to take on a responsibility for an
impossible situation, or one in which the risks are too great. You’ll have
to make the call based on your own ethics and judgment.

When you do accept the responsibility for an outcome, you should ex-
pect to be held accountable for it. When you make a mistake (as we all
do) or an error in judgment, admit it honestly and try to offer options.
The Pragmatic Programmer
2001/2/27 — Page 3 (tmp/responsibility)
Copyright 2001 Addison Wesley Longman, Inc

T HE C AT A TE M Y S OURCE C ODE 3

Don’t blame someone or something else, or make up an excuse. Don’t


blame all the problems on a vendor, a programming language, manage-
ment, or your coworkers. Any and all of these may play a role, but it is
up to you to provide solutions, not excuses.

If there was a risk that the vendor wouldn’t come through for you, then
you should have had a contingency plan. If the disk crashes—taking
all of your source code with it—and you don’t have a backup, it’s your
fault. Telling your boss “the cat ate my source code” just won’t cut it.

TIP 3

Provide Options, Don’t Make Lame Excuses

Before you approach anyone to tell them why something can’t be done,
is late, or is broken, stop and listen to yourself. Talk to the rubber
duck on your monitor, or the cat. Does your excuse sound reasonable,
or stupid? How’s it going to sound to your boss?

Run through the conversation in your mind. What is the other person
likely to say? Will they ask, “Have you tried this: : :” or “Didn’t you con-
sider that?” How will you respond? Before you go and tell them the bad
news, is there anything else you can try? Sometimes, you just know
what they are going to say, so save them the trouble.

Instead of excuses, provide options. Don’t say it can’t be done; explain


what can be done to salvage the situation. Does code have to be thrown
out? Educate them on the value of refactoring (see Refactoring, page
184). Do you need to spend time prototyping to determine the best way
to proceed (see Prototypes and Post-it Notes, page 53)? Do you need to
introduce better testing (see Code That’s Easy to Test, page 189, and
Ruthless Testing, page 237) or automation (see Ubiquitous Automation,
page 230) to prevent it from happening again? Perhaps you need ad-
ditional resources. Don’t be afraid to ask, or to admit that you need
help.

Try to flush out the lame excuses before voicing them aloud. If you
must, tell your cat first. After all, if little Tiddles is going to take the
blame. . . .
The Pragmatic Programmer
2001/2/27 — Page 4 (tmp/no_broken_windows)
Copyright 2001 Addison Wesley Longman, Inc

4 C HAPTER 1 A P RAGMATIC P HILOSOPHY

Related sections include:


 Prototypes and Post-it Notes, page 53
 Refactoring, page 184
 Code That’s Easy to Test, page 189
 Ubiquitous Automation, page 230
 Ruthless Testing, page 237

Challenges
 How do you react when someone—such as a bank teller, an auto mechanic,
or a clerk—comes to you with a lame excuse? What do you think of them
and their company as a result?

2 Software Entropy
While software development is immune from almost all physical laws,
entropy hits us hard. Entropy is a term from physics that refers to the
amount of “disorder” in a system. Unfortunately, the laws of thermo-
dynamics guarantee that the entropy in the universe tends toward a
maximum. When disorder increases in software, programmers call it
“software rot.”

There are many factors that can contribute to software rot. The most
important one seems to be the psychology, or culture, at work on a
project. Even if you are a team of one, your project’s psychology can
be a very delicate thing. Despite the best laid plans and the best peo-
ple, a project can still experience ruin and decay during its lifetime. Yet
there are other projects that, despite enormous difficulties and con-
stant setbacks, successfully fight nature’s tendency toward disorder
and manage to come out pretty well.

What makes the difference?

In inner cities, some buildings are beautiful and clean, while others
are rotting hulks. Why? Researchers in the field of crime and urban
decay discovered a fascinating trigger mechanism, one that very quickly
turns a clean, intact, inhabited building into a smashed and abandoned
derelict [WK82].
The Pragmatic Programmer
2001/2/27 — Page 5 (tmp/no_broken_windows)
Copyright 2001 Addison Wesley Longman, Inc

S OFTWARE E NTROPY 5

A broken window.

One broken window, left unrepaired for any substantial length of time,
instills in the inhabitants of the building a sense of abandonment—a
sense that the powers that be don’t care about the building. So another
window gets broken. People start littering. Graffiti appears. Serious
structural damage begins. In a relatively short space of time, the build-
ing becomes damaged beyond the owner’s desire to fix it, and the sense
of abandonment becomes reality.

The “Broken Window Theory” has inspired police departments in New


York and other major cities to crack down on the small stuff in order
to keep out the big stuff. It works: keeping on top of broken windows,
graffiti, and other small infractions has reduced the serious crime level.

TIP 4

Don’t Live with Broken Windows

Don’t leave “broken windows” (bad designs, wrong decisions, or poor


code) unrepaired. Fix each one as soon as it is discovered. If there is
insufficient time to fix it properly, then board it up. Perhaps you can
comment out the offending code, or display a "Not Implemented" mes-
sage, or substitute dummy data instead. Take some action to prevent
further damage and to show that you’re on top of the situation.

We’ve seen clean, functional systems deteriorate pretty quickly once


windows start breaking. There are other factors that can contribute to
software rot, and we’ll touch on some of them elsewhere, but neglect
accelerates the rot faster than any other factor.

You may be thinking that no one has the time to go around cleaning
up all the broken glass of a project. If you continue to think like that,
then you’d better plan on getting a dumpster, or moving to another
neighborhood. Don’t let entropy win.

Putting Out Fires


By contrast, there’s the story of an obscenely rich acquaintance of
Andy’s. His house was immaculate, beautiful, loaded with priceless
antiques, objets d’art, and so on. One day, a tapestry that was hang-
ing a little too close to his living room fireplace caught on fire. The fire
The Pragmatic Programmer
2001/2/27 — Page 6 (tmp/stone_soup)
Copyright 2001 Addison Wesley Longman, Inc

6 C HAPTER 1 A P RAGMATIC P HILOSOPHY

department rushed in to save the day—and his house. But before they
dragged their big, dirty hoses into the house, they stopped—with the
fire raging—to roll out a mat between the front door and the source of
the fire.

They didn’t want to mess up the carpet.

A pretty extreme case, to be sure, but that’s the way it must be with
software. One broken window—a badly designed piece of code, a poor
management decision that the team must live with for the duration
of the project—is all it takes to start the decline. If you find yourself
working on a project with quite a few broken windows, it’s all too easy
to slip into the mindset of “All the rest of this code is crap, I’ll just follow
suit.” It doesn’t matter if the project has been fine up to this point.
In the original experiment leading to the “Broken Window Theory,” an
abandoned car sat for a week untouched. But once a single window was
broken, the car was stripped and turned upside down within hours.

By the same token, if you find yourself on a team and a project where
the code is pristinely beautiful—cleanly written, well designed, and
elegant—you will likely take extra special care not to mess it up, just
like the firefighters. Even if there’s a fire raging (deadline, release date,
trade show demo, etc.), you don’t want to be the first one to make a
mess.

Related sections include:


 Stone Soup and Boiled Frogs, page 7
 Refactoring, page 184
 Pragmatic Teams, page 224

Challenges
 Help strengthen your team by surveying your computing “neighborhood.”
Choose two or three “broken windows” and discuss with your colleagues
what the problems are and what could be done to fix them.

 Can you tell when a window first gets broken? What is your reaction? If
it was the result of someone else’s decision, or a management edict, what
can you do about it?
The Pragmatic Programmer
2001/2/27 — Page 7 (tmp/stone_soup)
Copyright 2001 Addison Wesley Longman, Inc

S TONE S OUP AND B OILED F ROGS 7

3 Stone Soup and Boiled Frogs


The three soldiers returning home from war were hungry. When they saw the
village ahead their spirits lifted—they were sure the villagers would give them
a meal. But when they got there, they found the doors locked and the windows
closed. After many years of war, the villagers were short of food, and hoarded
what they had.

Undeterred, the soldiers boiled a pot of water and carefully placed three stones
into it. The amazed villagers came out to watch.

“This is stone soup,” the soldiers explained. “Is that all you put in it?” asked
the villagers. “Absolutely—although some say it tastes even better with a few
carrots: : : .” A villager ran off, returning in no time with a basket of carrots from
his hoard.

A couple of minutes later, the villagers again asked “Is that it?”

“Well,” said the soldiers, “a couple of potatoes give it body.” Off ran another
villager.

Over the next hour, the soldiers listed more ingredients that would enhance the
soup: beef, leeks, salt, and herbs. Each time a different villager would run off to
raid their personal stores.

Eventually they had produced a large pot of steaming soup. The soldiers removed
the stones, and they sat down with the entire village to enjoy the first square
meal any of them had eaten in months.

There are a couple of morals in the stone soup story. The villagers are
tricked by the soldiers, who use the villagers’ curiosity to get food from
them. But more importantly, the soldiers act as a catalyst, bringing
the village together so they can jointly produce something that they
couldn’t have done by themselves—a synergistic result. Eventually ev-
eryone wins.

Every now and then, you might want to emulate the soldiers.

You may be in a situation where you know exactly what needs doing
and how to do it. The entire system just appears before your eyes—you
know it’s right. But ask permission to tackle the whole thing and you’ll
be met with delays and blank stares. People will form committees, bud-
gets will need approval, and things will get complicated. Everyone will
guard their own resources. Sometimes this is called “start-up fatigue.”
The Pragmatic Programmer
2001/2/27 — Page 8 (tmp/stone_soup)
Copyright 2001 Addison Wesley Longman, Inc

8 C HAPTER 1 A P RAGMATIC P HILOSOPHY

It’s time to bring out the stones. Work out what you can reasonably
ask for. Develop it well. Once you’ve got it, show people, and let them
marvel. Then say “of course, it would be better if we added: : : .” Pretend
it’s not important. Sit back and wait for them to start asking you to
add the functionality you originally wanted. People find it easier to join
an ongoing success. Show them a glimpse of the future and you’ll get
them to rally around.1

TIP 5

Be a Catalyst for Change

The Villagers’ Side


On the other hand, the stone soup story is also about gentle and grad-
ual deception. It’s about focusing too tightly. The villagers think about
the stones and forget about the rest of the world. We all fall for it, every
day. Things just creep up on us.

We’ve all seen the symptoms. Projects slowly and inexorably get totally
out of hand. Most software disasters start out too small to notice, and
most project overruns happen a day at a time. Systems drift from their
specifications feature by feature, while patch after patch gets added to
a piece of code until there’s nothing of the original left. It’s often the
accumulation of small things that breaks morale and teams.

TIP 6

Remember the Big Picture

We’ve never tried this—honest. But they say that if you take a frog and
drop it into boiling water, it will jump straight back out again. However,
if you place the frog in a pan of cold water, then gradually heat it, the
frog won’t notice the slow increase in temperature and will stay put
until cooked.

1. While doing this, you may be comforted by the line attributed to Rear Admiral Dr.
Grace Hopper: “It’s easier to ask forgiveness than it is to get permission.”
The Pragmatic Programmer
2001/2/27 — Page 9 (tmp/good_enough_sw)
Copyright 2001 Addison Wesley Longman, Inc

G OOD -E NOUGH S OFTWARE 9

Note that the frog’s problem is different from the broken windows issue
discussed in Section 2. In the Broken Window Theory, people lose the
will to fight entropy because they perceive that no one else cares. The
frog just doesn’t notice the change.

Don’t be like the frog. Keep an eye on the big picture. Constantly review
what’s happening around you, not just what you personally are doing.

Related sections include:


 Software Entropy, page 4
 Programming by Coincidence, page 172
 Refactoring, page 184
 The Requirements Pit, page 202
 Pragmatic Teams, page 224

Challenges
 While reviewing a draft of this book, John Lakos raised the following is-
sue: The soldiers progressively deceive the villagers, but the change they
catalyze does them all good. However, by progressively deceiving the frog,
you’re doing it harm. Can you determine whether you’re making stone
soup or frog soup when you try to catalyze change? Is the decision subjec-
tive or objective?

4 Good-Enough Software
Striving to better, oft we mar what’s well.
King Lear 1.4

There’s an old(ish) joke about a U.S. company that places an order for
100,000 integrated circuits with a Japanese manufacturer. Part of the
specification was the defect rate: one chip in 10,000. A few weeks later
the order arrived: one large box containing thousands of ICs, and a
small one containing just ten. Attached to the small box was a label
that read: “These are the faulty ones.”
The Pragmatic Programmer
2001/2/27 — Page 10 (tmp/good_enough_sw)
Copyright 2001 Addison Wesley Longman, Inc

10 C HAPTER 1 A P RAGMATIC P HILOSOPHY

If only we really had this kind of control over quality. But the real
world just won’t let us produce much that’s truly perfect, particularly
not bug-free software. Time, technology, and temperament all conspire
against us.

However, this doesn’t have to be frustrating. As Ed Yourdon described


in an article in IEEE Software [You95], you can discipline yourself to
write software that’s good enough—good enough for your users, for fu-
ture maintainers, for your own peace of mind. You’ll find that you are
more productive and your users are happier. And you may well find
that your programs are actually better for their shorter incubation.

Before we go any further, we need to qualify what we’re about to say.


The phrase “good enough” does not imply sloppy or poorly produced
code. All systems must meet their users’ requirements to be success-
ful. We are simply advocating that users be given an opportunity to
participate in the process of deciding when what you’ve produced is
good enough.

Involve Your Users in the Trade-Off


Normally you’re writing software for other people. Often you’ll remem-
ber to get requirements from them.2 But how often do you ask them
how good they want their software to be? Sometimes there’ll be no
choice. If you’re working on pacemakers, the space shuttle, or a low-
level library that will be widely disseminated, the requirements will
be more stringent and your options more limited. However, if you’re
working on a brand new product, you’ll have different constraints. The
marketing people will have promises to keep, the eventual end users
may have made plans based on a delivery schedule, and your company
will certainly have cash-flow constraints. It would be unprofessional to
ignore these users’ requirements simply to add new features to the pro-
gram, or to polish up the code just one more time. We’re not advocating
panic: it is equally unprofessional to promise impossible time scales
and to cut basic engineering corners to meet a deadline.

2. That was supposed to be a joke!


The Pragmatic Programmer
2001/2/27 — Page 11 (tmp/good_enough_sw)
Copyright 2001 Addison Wesley Longman, Inc

G OOD -E NOUGH S OFTWARE 11

The scope and quality of the system you produce should be specified
as part of that system’s requirements.

TIP 7

Make Quality a Requirements Issue

Often you’ll be in situations where trade-offs are involved. Surprisingly,


many users would rather use software with some rough edges today
than wait a year for the multimedia version. Many IT departments with
tight budgets would agree. Great software today is often preferable to
perfect software tomorrow. If you give your users something to play with
early, their feedback will often lead you to a better eventual solution (see
Tracer Bullets, page 48).

Know When to Stop


In some ways, programming is like painting. You start with a blank
canvas and certain basic raw materials. You use a combination of sci-
ence, art, and craft to determine what to do with them. You sketch
out an overall shape, paint the underlying environment, then fill in the
details. You constantly step back with a critical eye to view what you’ve
done. Every now and then you’ll throw a canvas away and start again.

But artists will tell you that all the hard work is ruined if you don’t
know when to stop. If you add layer upon layer, detail over detail, the
painting becomes lost in the paint.

Don’t spoil a perfectly good program by overembellishment and over-


refinement. Move on, and let your code stand in its own right for a
while. It may not be perfect. Don’t worry: it could never be perfect. (In
Chapter 6, page 171, we’ll discuss philosophies for developing code in
an imperfect world.)

Related sections include:


 Tracer Bullets, page 48
 The Requirements Pit, page 202
 Pragmatic Teams, page 224
 Great Expectations, page 255
The Pragmatic Programmer
2001/2/27 — Page 12 (tmp/knowledge)
Copyright 2001 Addison Wesley Longman, Inc

12 C HAPTER 1 A P RAGMATIC P HILOSOPHY

Challenges
 Look at the manufacturers of the software tools and operating systems that
you use. Can you find any evidence that these companies are comfortable
shipping software they know is not perfect? As a user, would you rather
(1) wait for them to get all the bugs out, (2) have complex software and
accept some bugs, or (3) opt for simpler software with fewer defects?

 Consider the effect of modularization on the delivery of software. Will it


take more or less time to get a monolithic block of software to the required
quality compared with a system designed in modules? Can you find com-
mercial examples?

5 Your Knowledge Portfolio


An investment in knowledge always pays the best interest.
Benjamin Franklin

Ah, good old Ben Franklin—never at a loss for a pithy homily. Why, if we
could just be early to bed and early to rise, we’d be great programmers—
right? The early bird might get the worm, but what happens to the early
worm?

In this case, though, Ben really hit the nail on the head. Your knowledge
and experience are your most important professional assets.

Unfortunately, they’re expiring assets.3 Your knowledge becomes out of


date as new techniques, languages, and environments are developed.
Changing market forces may render your experience obsolete or irrele-
vant. Given the speed at which Web-years fly by, this can happen pretty
quickly.

As the value of your knowledge declines, so does your value to your


company or client. We want to prevent this from ever happening.

3. An expiring asset is something whose value diminishes over time. Examples include
a warehouse full of bananas and a ticket to a ball game.
The Pragmatic Programmer
2001/2/27 — Page 13 (tmp/knowledge)
Copyright 2001 Addison Wesley Longman, Inc

Y OUR K NOWLEDGE P OR TFOLIO 13

Your Knowledge Portfolio


We like to think of all the facts programmers know about computing,
the application domains they work in, and all their experience as their
Knowledge Portfolios. Managing a knowledge portfolio is very similar to
managing a financial portfolio:

1. Serious investors invest regularly—as a habit.

2. Diversification is the key to long-term success.

3. Smart investors balance their portfolios between conservative and


high-risk, high-reward investments.

4. Investors try to buy low and sell high for maximum return.

5. Portfolios should be reviewed and rebalanced periodically.

To be successful in your career, you must manage your knowledge port-


folio using these same guidelines.

Building Your Portfolio


 Invest regularly. Just as in financial investing, you must invest in
your knowledge portfolio regularly. Even if it’s just a small amount,
the habit itself is as important as the sums. A few sample goals are
listed in the next section.

 Diversify. The more different things you know, the more valuable
you are. As a baseline, you need to know the ins and outs of the
particular technology you are working with currently. But don’t
stop there. The face of computing changes rapidly—hot technology
today may well be close to useless (or at least not in demand) to-
morrow. The more technologies you are comfortable with, the better
you will be able to adjust to change.

 Manage risk. Technology exists along a spectrum from risky,


potentially high-reward to low-risk, low-reward standards. It’s not
a good idea to invest all of your money in high-risk stocks that
might collapse suddenly, nor should you invest all of it conserva-
tively and miss out on possible opportunities. Don’t put all your
technical eggs in one basket.
The Pragmatic Programmer
2001/2/27 — Page 14 (tmp/knowledge)
Copyright 2001 Addison Wesley Longman, Inc

14 C HAPTER 1 A P RAGMATIC P HILOSOPHY

 Buy low, sell high. Learning an emerging technology before it be-


comes popular can be just as hard as finding an undervalued stock,
but the payoff can be just as rewarding. Learning Java when it first
came out may have been risky, but it paid off handsomely for the
early adopters who are now at the top of that field.

 Review and rebalance. This is a very dynamic industry. That hot


technology you started investigating last month might be stone cold
by now. Maybe you need to brush up on that database technology
that you haven’t used in a while. Or perhaps you could be bet-
ter positioned for that new job opening if you tried out that other
language. . . .

Of all these guidelines, the most important one is the simplest to do:

TIP 8

Invest Regularly in Your Knowledge Portfolio

Goals
Now that you have some guidelines on what and when to add to your
knowledge portfolio, what’s the best way to go about acquiring intellec-
tual capital with which to fund your portfolio? Here are a few sugges-
tions.

 Learn at least one new language every year. Different languages


solve the same problems in different ways. By learning several dif-
ferent approaches, you can help broaden your thinking and avoid
getting stuck in a rut. Additionally, learning many languages is far
easier now, thanks to the wealth of freely available software on the
Internet (see page 267).

 Read a technical book each quarter. Bookstores are full of techni-


cal books on interesting topics related to your current project. Once
you’re in the habit, read a book a month. After you’ve mastered the
technologies you’re currently using, branch out and study some
that don’t relate to your project.

 Read nontechnical books, too. It is important to remember that


computers are used by people—people whose needs you are trying
to satisfy. Don’t forget the human side of the equation.
The Pragmatic Programmer
2001/2/27 — Page 15 (tmp/knowledge)
Copyright 2001 Addison Wesley Longman, Inc

Y OUR K NOWLEDGE P OR TFOLIO 15

 Take classes. Look for interesting courses at your local commu-


nity college or university, or perhaps at the next trade show that
comes to town.

 Participate in local user groups. Don’t just go and listen, but


actively participate. Isolation can be deadly to your career; find out
what people are working on outside of your company.

 Experiment with different environments. If you’ve worked only in


Windows, play with Unix at home (the freely available Linux is per-
fect for this). If you’ve used only makefiles and an editor, try an
IDE, and vice versa.

 Stay current. Subscribe to trade magazines and other journals


(see page 262 for recommendations). Choose some that cover tech-
nology different from that of your current project.

 Get wired. Want to know the ins and outs of a new language or
other technology? Newsgroups are a great way to find out what
experiences other people are having with it, the particular jargon
they use, and so on. Surf the Web for papers, commercial sites,
and any other sources of information you can find.

It’s important to continue investing. Once you feel comfortable with


some new language or bit of technology, move on. Learn another one.

It doesn’t matter whether you ever use any of these technologies on a


project, or even whether you put them on your resume. The process of
learning will expand your thinking, opening you to new possibilities and
new ways of doing things. The cross-pollination of ideas is important;
try to apply the lessons you’ve learned to your current project. Even if
your project doesn’t use that technology, perhaps you can borrow some
ideas. Get familiar with object orientation, for instance, and you’ll write
plain C programs differently.

Opportunities for Learning


So you’re reading voraciously, you’re on top of all the latest breaking
developments in your field (not an easy thing to do), and somebody
asks you a question. You don’t have the faintest idea what the answer
is, and freely admit as much.
The Pragmatic Programmer
2001/2/27 — Page 16 (tmp/knowledge)
Copyright 2001 Addison Wesley Longman, Inc

16 C HAPTER 1 A P RAGMATIC P HILOSOPHY

Don’t let it stop there. Take it as a personal challenge to find the answer.
Ask a guru. (If you don’t have a guru in your office, you should be able
to find one on the Internet: see the box on on the facing page.) Search
the Web. Go to the library.4

If you can’t find the answer yourself, find out who can. Don’t let it rest.
Talking to other people will help build your personal network, and you
may surprise yourself by finding solutions to other, unrelated problems
along the way. And that old portfolio just keeps getting bigger. . . .

All of this reading and researching takes time, and time is already in
short supply. So you need to plan ahead. Always have something to
read in an otherwise dead moment. Time spent waiting for doctors and
dentists can be a great opportunity to catch up on your reading—but be
sure to bring your own magazine with you, or you might find yourself
thumbing through a dog-eared 1973 article about Papua New Guinea.

Critical Thinking
The last important point is to think critically about what you read
and hear. You need to ensure that the knowledge in your portfolio is
accurate and unswayed by either vendor or media hype. Beware of the
zealots who insist that their dogma provides the only answer—it may
or may not be applicable to you and your project.

Never underestimate the power of commercialism. Just because a Web


search engine lists a hit first doesn’t mean that it’s the best match; the
content provider can pay to get top billing. Just because a bookstore
features a book prominently doesn’t mean it’s a good book, or even
popular; they may have been paid to place it there.

TIP 9

Critically Analyze What You Read and Hear

Unfortunately, there are very few simple answers anymore. But with
your extensive portfolio, and by applying some critical analysis to the

4. In this era of the Web, many people seem to have forgotten about real live libraries
filled with research material and staff.
The Pragmatic Programmer
2001/2/27 — Page 17 (tmp/knowledge)
Copyright 2001 Addison Wesley Longman, Inc

Y OUR K NOWLEDGE P OR TFOLIO 17

Care and Cultivation of Gurus


With the global adoption of the Internet, gurus suddenly are as close
as your Enter key. So, how do you find one, and how do you get one
to talk with you?
We find there are some simple tricks.
 Know exactly what you want to ask, and be as specific as you
can be.
 Frame your question carefully and politely. Remember that you’re
asking a favor; don’t seem to be demanding an answer.
 Once you’ve framed your question, stop and look again for the
answer. Pick out some keywords and search the Web. Look for
appropriate FAQs (lists of frequently asked questions with an-
swers).
 Decide if you want to ask publicly or privately. Usenet news-
groups are wonderful meeting places for experts on just about
any topic, but some people are wary of these groups’ public
nature. Alternatively, you can always e-mail your guru directly.
Either way, use a meaningful subject line. (“Need Help!!!”
doesn’t cut it.)
 Sit back and be patient. People are busy, and it may take days to
get a specific answer.
Finally, please be sure to thank anyone who responds to you. And if
you see people asking questions you can answer, play your part and
participate.

torrent of technical publications you will read, you can understand the
complex answers.

Challenges
 Start learning a new language this week. Always programmed in C++? Try
Smalltalk [URL 13] or Squeak [URL 14]. Doing Java? Try Eiffel [URL 10]
or TOM [URL 15]. See page 267 for sources of other free compilers and
environments.

 Start reading a new book (but finish this one first!). If you are doing very
detailed implementation and coding, read a book on design and architec-
ture. If you are doing high-level design, read a book on coding techniques.
Try Safari Books Online FREE
Get online access to 7,500+ Books and Videos

Free Trial—Get Started Today!


informit.com/safaritrial

Find trusted answers, fast


Only Safari lets you search across thousands of best-selling books from the top
technology publishers, including Addison-Wesley Professional, Cisco Press,
O’Reilly, Prentice Hall, Que, and Sams.

Master the latest tools and techniques


In addition to gaining access to an incredible inventory of technical books,
Safari’s extensive collection of video tutorials lets you learn from the leading
video training experts.

Wait, there’s more!


Keep your competitive edge
With Rough Cuts, get access to the developing manuscript and be among the first
to learn the newest technologies.

Stay current with emerging technologies


Short Cuts and Quick Reference Sheets are short, concise, focused content
created to get you up-to-speed quickly on new and cutting-edge technologies.
LearnIT at InformIT
IT Tr a n s
ad por
Re t IT

A
b
IT Books eBooks

so
h

rb
tc
Ca

IT
Podcasts Short Cuts
IT

Foll
Engage

ow I T
Conferences Rough Cuts

Reference Safari Books

IT
Guides Online
Cit

ch
e

ar
IT

Blogs Video Se

D Articles
is IT
cu
ss ch
IT at
W
Resea rch IT

11 ways to learn IT AT
www.InformIT.com/learn
Get Behind the Scenes
Stay Ahead of the Curve
Rough Cuts is a Safari Books Online interactive publishing service that provides you
with first access to pre-published manuscripts on cutting-edge technology topics
— enabling you to stay on the cutting-edge and remain competitive. When you
participate in the Rough Cuts program, you also own an important role in helping
to develop manuscripts into best-selling books.
Here’s how it works:
1. Select a Rough Cuts title.
2. Get access through a Safari Library account. Or if you would like,
you can order a single Rough Cuts title as well.
3. Sign up to receive Alerts by visiting the Rough Cuts catalog page.
4. Read updated versions online or in PDF at your convenience.
5. Interact with the Rough Cuts community. Post your feedback
or respond to comments from other users, editors, and authors.
6. Access the final version – online access and PDF access of the
printed version is available for up to 45 days.

9780137013951 9780321648976 9780321592156 9780137151424

View Titles Available and Purchase Rough Cuts at


informit.com/roughcuts

informIT.com The Trusted Technology Learning Source


• L
 iveLessons allows you to keep LiveLessons: self-paced, personal
your skills up to date with the video instruction from the world’s
latest technology training from leading technology experts
trusted author experts. • INSTRUCTORS YOU TRUST
• Cutting edge topics
• L
 iveLessons is a cost effective • CUSTOMIZED, SELF-PACED
alternative to expensive off-site LEARNING
training programs. • LEARN BY DOING

• L
 iveLessons provides the ability
to learn at your own pace and
avoid hours in a classroom.

Package includes:
• 1 DVD featuring 3 - 8 hours of
instructor-led classroom sessions
divided into 15-20 minute
step-by-step hands-on labs
• S ample code and printed
study guide

The power of the world’s leading experts at your fingertips!

To learn more about LiveLessons visit


mylivelessons.com
www.informit.com/usergroups

Part of a
User Group?
Are you a member of a group that
meets to discuss IT-related topics?
Your group may be eligible for the
Pearson User Group Program!

Benefits include :
• Member discount of 35%
• Monthly review copies
• Information materials and more!

To learn if your group qualifies visit


www.informit.com/usergroups

Das könnte Ihnen auch gefallen