JTF > Rationale > Problem Taxonomy

Chapter 3
Taxonomy of Problems in Teaching Java


Before it is possible to search for solutions to the problems involved in teaching Java at the introductory level, it is essential to know what those problems are. To this end, one of the first tasks that the Java Task Force undertook was to survey the literature of computer science education in an attempt to identify the problems that have generated the greatest level of concern.

On the basis of that survey, we have divided the pedagogical problems associated with Java into three categories: high-level issues that are in some sense beyond the details of the language itself, language issues that arise from the design of Java itself, and API issues associated with the application programmer interfaces provided as part of Sun’s standard Java releases. The issues in each of these categories are shown in Figure 3-1 along with a capsule assessment of their current status as problems for the community.

Figure 3-1. Summary of issues identified by the Java Task Force

   High-level issues:
      H1.Scale(remains a concern)
      H2.Instability(remains a concern)
      H3.Speed of execution(improving over time)
      H4.Lack of good textbooks and environments(improving over time)
 
   Language issues:
      L1.Static methods, including main(remains a concern)
      L2.Exceptions(remains a concern)
      L3.Poor separation of interface and implementation  (partly addressed by tools)
      L4.Wrapper classes(added in Java 5.0)
      L5.Lack of parameterized classes (templates)(added in Java 5.0)
      L6.Lack of enumerated types(added in Java 5.0)
      L7.Inability to code preconditions(added in JDK 1.4)
      L8.Lack of an iterator syntax(added in Java 5.0)
      L9.Low-level concerns(disposition varies)
 
   API issues:
      A1.Lack of a simple input mechanism(remains a concern)
      A2.Conceptual difficulty of the graphics model(remains a concern)
      A3.GUI components inappropriate for beginners(remains a concern)
      A4.Inadequate support for event-driven code(remains a concern)

As the annotations in the right-hand column indicate, many of the problems with Java reported in the literature have been at least partially addressed, either by incremental improvements over time or by new releases of the Java environment. Version 1.4 of the Java Development Kit (JDK), for example, added an assertion mechanism to Java, thereby enabling the specification of preconditions [Zukowski02]. The many changes—parameterized types, enumeration types, boxing and unboxing of primitive data, an extension to the for statement syntax to support iteration, and new APIs to support concurrency and formatted I/O—introduced in Java 5.0 [Austin04, Heiss03] will have an even more dramatic effect on pedagogy.

While the release of Java 5.0 is likely to solve several problems, its adoption in the near term represents a significant challenge to the educational community. Sun released Standard Edition 5.0 of the Java 2 Platform (J2SE 5.0) only in September 2004, and it remains unclear how quickly educational institutions will be able to adopt it. Moreover, given that we have very little experience teaching using the new language features included in Java 5.0, there is no direct evidence to indicate how well the new facilities will work in the classroom. In light of this uncertainty, the Java Task Force has decided that its recommendations must be implementable, at least in part, by those who continue to use earlier versions of Java.

The sections that follow offer additional details on the set of problems we have identified from the literature.

3.1 High-level issues

This section outlines those challenges that in some sense transcend the details of the Java language and its libraries. These concerns therefore represent a set of meta-level issues that as often as not are intrinsic to the character of modern programming languages. They are nonetheless quite important in terms of their practical impact on teaching Java.

H1. Scale

At some level, the most serious problem facing instructors who try to teach Java—or any modern industrial-strength language for that matter—is the problem of scale. While such languages may themselves be reasonably simple, writing any useful programs requires the use of classes supplied as application programmer interfaces (APIs) along with the language. For modern languages, such API collections are vast. The existence of these huge libraries makes it difficult for students and teachers to learn the language without suffering from conceptual overload. This point was made elegantly in Niklaus Wirth’s invited address at ITiCSE’02 [Wirth02] and has also been addressed by other writers in recent years [Hadjerrouit98, Roberts01, Roberts04a].

The problem of overwhelming scale is also unlikely to diminish as time goes on. Each release of Java is larger than its predecessor, which only adds to the scale problem. Java 5.0 [Austin04, Heiss03], in particular, adds considerable complexity to the language, even as it addresses many of the problems identified in earlier versions. Some critics of Java 5.0 have gone so far as to argue that the added complexity in the new release might spell the “end of Java” [Cooper03], although the jury is clearly still out on this question.

We believe that the best way to address the problem of scale is to define a subset of Java and its APIs that reduce the level of detail complexity while enabling a variety of approaches to introductory computer science education. This goal is reflected in the first two deliverables as described in the summary of the special session on the Java Task Force at SIGCSE’04 [Roberts04b]:

  1. A definition of a subset of the standard Java APIs appropriate for first-year computer science. This subset would involve restricting both the number of classes used as well as the number of public methods made visible within those classes. Note that this subset must be sufficient to have students write significant applications using Java. To this end, it will presumably be a superset of the AP Java subset [Astrachan00] which seeks to define what aspects of the language will be tested on the AP exam.

  2. A public web site containing an updated JavaDoc reference manual for the approved Java subset. This web site would make it possible for students to browse the standard classes and methods defined in the subset without being overwhelmed by classes, methods, and concepts they are unlikely to use. For the classes and methods that are included, the web site will contain more examples and tutorial material than is currently supplied with the Java APIs.

It is important to understand that the Task Force is not seeking to define a minimal subset, but rather a subset that is rich enough to support different pedagogical strategies while still providing some relief from the overwhelming scale and complexity that adhere to the full-blown releases of Java. There is, moreover, nothing to prevent an individual instructor from venturing beyond the limits provided by the subset. In fact, we encourage instructors to experiment with Java classes—whether home-grown or part of the standard Java release—whenever such classes can be used to advance computer science pedagogy.

H2. Instability

The problem of scale is reinforced by the fact that Java continues to evolve rapidly. As a result, pedagogical materials must be redesigned on an ongoing basis, making it difficult for both those who create those materials and those who try to use them. One of the goals of the ACM Java Task Force is to provide a modicum of stability by defining the standard Java subset in a way that insulates adopters from at least some of the rapid evolution going on in the Java community. A more complete discussion of the nature of this instability along with some of the underlying reasons why it occurs can be found in the background paper presented at SIGCSE’04 [Roberts04a].

H3. Speed of execution

Many of the early papers describing classroom experience with Java [Bergin98, King97, Tyma98] cite the relatively slow execution time of Java programs as a problem. Because Java is compiled to a virtual machine rather than the instruction set of the underlying hardware, Java will never have the runtime efficiency of programs in C or C++. Even so, the situation has improved markedly since the early days of Java. If nothing else, the increase in processor speed means that most users now see much faster execution times than they did a few years ago. In addition, the development of just-in-time compiler technology (JIC) means that the Java runtime environment tends to run much faster on frequently executed portions of code.

H4. Lack of good textbooks and environments

Most of the early adopters of Java complained about the shortage of usable textbooks and teaching environments, but that problem has certainly been alleviated in recent years. At this point in time, there are far too many Java textbooks to list, many of which have been used effectively in introductory courses. There are, moreover, a number of Java-based environments that have been used successfully in the classroom, including BlueJ [Kölling00], DrJava [Allen02], and jGRASP [Cross04]. It does not seem appropriate for the ACM Java Task Force to endorse any specific textbooks or commercial development environments. At the same time, it is important to ensure that the strategies we recommend work in as many of the leading environments as possible.

3.2 Language issues

The following problems arise from the details of the Java language itself, as opposed to the associated APIs. Because it is generally harder to change the language definition than it is to provide an alternative for an API, these problems are likely to be more difficult to solve than those described in section 3.2 on “API issues.”

L1. Static methods (including main)

One of the common complaints about Java to emerge in papers from recent years is the fact that beginning students must come to grips with static methods too early in the first course [Biddle98, Martin98, Reges00, Reges02]. Part of the problem comes from the fact that the standard mathematical functions are implemented as static methods in the Math class, forcing students to understand that the call Math.sqrt(x), for example, is different from most method invocations in that there is no object to which a message is sent. For better or worse, Java 5.0 allows one to import all static methods and constants from a class. Thus, if the programmer includes the line

 

import static Math.*;

one can subsequently drop the Math prefix and simply invoke sqrt(x). While such a change may make the resulting code easier for students, the conceptual distinction has not gone away, and it is still necessary to explain the differences between static and nonstatic method invocation.

The heart of the problem, however, is not the existence of static methods in the public APIs as much as the fact that Java applications, as opposed to applets, are invoked statically through a call to the method

 

public static void main(String[] args)

The need to include a main method introduces—presumably on day one of the course—a whole host of confusing issues including the keywords public, static, and void, the class String, and the empty-bracket syntax for designating an array parameter. To some extent, these problems can be finessed simply by declaring the syntax to be a bit of arcane boilerplate whose meaning will become clear in the fullness of time. The more difficult problem is that the main method is invoked without instantiating an object, which means that any subsidiary methods must also be declared as static. Moreover, the entire idea of object-oriented behavior is undermined through this mechanism.

The situation is very different with applets. When you execute an applet, the browser creates a new object of the appropriate applet subclass and then sends messages like init and start to the newly instantiated object. The applet paradigm is thus considerably more object-oriented, although it has other problems of its own. Developing a mechanism to make application invocation more object-oriented and to reduce the asymmetry between the two models would be of considerable pedagogic value.

L2. Exceptions

Many of the early reports on using Java as an introductory language express concern about the fact that the definitions of various library APIs make it impossible to ignore the concept of exceptions, even in simple examples [Biddle98, Hosch96, Weiss98, Roberts01]. The classic illustration of this problem occurs when the programmer wants to specify a delay in execution. The static method Thread.sleep offers the necessary functionality, but it is not possible to write

 

Thread.sleep(time);

because Thread.sleep can throw InterruptedException, which must be caught by the client, as follows:

 

try {
   Thread.sleep(time);
} catch (InterruptedException ex) {
   This exception is typically ignored.
}

Similar problems with exceptions also occur during I/O operations, which exacerbates the problems that arise under topic A1 (Lack of a simple input mechanism).

The rules concerning exceptions and the list of exceptions raised by the existing Java APIs are beyond the boundaries of what this Task Force can change. The only thing that the Task Force can do—as many who have implemented Java libraries have done—is to provide additional mechanism that allow novices to accomplish the most common operations without having to deal with the exceptions. The graphics libraries developed at Williams [Bruce01] and Stanford [Roberts98], for example, both include a pause method whose implementation encapsulates the exception-handling phase of the Thread.sleep call.

L3. Poor separation of interface and implementation

Several of the critical reviews of Java as a teaching language point out that Java makes it harder to separate the high-level specification of what a class does from the low-level implementation that determines how it does it [Biddle98, Hosch96, Roberts01]. The crux of the problem is that Java classes, unlike those of C++, do not have a separate specification section that includes the prototypes of the methods but not their bodies. As a result, anyone who looks at the code for a class is forced to see all of the detail rather than a more abstract specification indicating what the client needs to know.

While it is impossible to fix this problem within the confines of the Java definition, sensitivity to the value of separating interface-level specification from the underlying implementation has an effect both on pedagogical strategy and the design of new classes for teaching. Abstract classes and interfaces each provide some level of relief from this concern. Another approach altogether is to rely on documentation tools (such as javadoc) and programming environments to provide the conceptual separation between specification and implementation that the language lacks.

L4. Wrapper classes

At the language level, one of the most often cited concerns in the past has been the distinction between primitive types such as int, boolean, and double from the corresponding full-fledged counterparts (typically called wrapper classes) Integer, Boolean, and Double [Biddle98, Reges02, Roberts01]. The problem with the distinction between these two categories is partly the conceptual overload students feel when they try to understand why there are two distinct flavors of what seem to be the same thing. In practical terms, working with primitive types introduces considerable extra complexity whenever those values are introduced into a container. It is, for example, impossible to add an int value n to an array list using the otherwise intuitive code

 

list.add(n);

because the value of n is a primitive type rather than an object. Historically, Java has insisted that the programmer explicitly allocate the corresponding Integer object before invoking add, as follows:

 

list.add(new Integer(n));

Similarly, the programmer must also specify the corresponding reverse conversion when removing a primitive value from a collection. To retrieve the first integer from list and assign it to the variable first requires the incantation

 

first = ((Integer) list.get(0)).intValue();

which is certain to confuse most novices.

Fortunately, this problem—particularly when one also makes use of the template mechanism described in the following section—goes away in Java 5.0. The new 5.0 release includes automatic “boxing” and “unboxing” of the primitive types so that the preceding insertion and selection operations can be reduced to

 

list.add(n);

and

 

first = list.get(0);

assuming that list is declared as an ArrayList<Integer>.

L5. Lack of parameterized classes

Another widespread complaint about Java is that the language does not support strongly typed collections because it lacks a counterpart to the C++ template facility [Biddle98, Hadjerrouit98, Hosch96, Martin98]. Java 5.0 introduces a structure for parameterized types in a way that eliminates many problems associated with the C++ implementation of this mechanism while retaining the convenience of the syntax. This mechanism, which is usually called generics in Java, has also been retrofitted into the Java collection framework so that it is possible, for example, to declare an array list of integers by writing

 

ArrayList<Integer> list;

or a hash table containing strings by

 

HashMap<String> dictionary;

Judging from the documentation and examples, parameterized types in Java unfortunately introduce a number of complex and potentially confusing issues, but it should be possible to avoid such complexity in classroom settings either by limiting their use to the standard collections framework or by imposing judicious restrictions on the ways in which type parameters can be used. It is, however, difficult to assess whether generics will succeed with an introductory audience until people have had a chance to experiment with it.

L6. Lack of enumerated types

Another weakness in the Java type system that has attracted wide attention is the lack of enumerated types of the sort available in Pascal, C, and C++ [Biddle98, Hosch96, Reges02]. Java 5.0 introduces enumerated types, and it should be possible for instructors to use these in much the same way that they have in those other languages.

L7. Inability to code preconditions

In one of the very early papers to discuss Java as a teaching language, Frederick Hosch expressed concern that Java included no mechanism for specifying runtime assertions to check the preconditions of a method, such as those provided in C and C++ by the assert facility [Hosch96]. Assertions have become part of Java as of release 1.4, so that this problem is now historical. Interestingly, however, the documentation of release 1.4 specifically discourages the use of assert to enforce preconditions, arguing that such failures are more properly handled by raising an illegal argument exception.

L8. Lack of an iterator syntax

In his comparison of Java and C#, Stuart Reges expresses a fondness for the foreach statement in C# [Reges02]. Other writers have expressed similar views about the pedagogic value of including syntactic support for iteration [Roberts01]. Java 5.0 includes a new syntax for iteration based on the for statement, making it possible, for example, to iterate over the elements in a variable list of type ArrayList<Integer> by writing

 

for (Integer i : list) {
   Body of loop
}

L9. Low-level concerns

In the interest of completeness, it is useful to identify a few other features of Java that have been cited in the literature as problems:

Each of these concerns represents an issue that is on the one hand deeply embedded in the design of Java and on the other hand of relatively minor consequence. The Java Task Force has no plans to address these concerns other than by encouraging the use of coding styles that minimize the associated problems.

3.3 API issues

This final category of documented problems in Java concerns the limitations of the existing APIs.

A1. Lack of a simple input mechanism

By far the most widely cited problem in papers about Java is the lack of any simple facility for accepting input from the user [Grissom00, Koffman01, Martin98, Reges02, Roberts01, Wallace99, Weiss98, Wolz99]. Many textbook authors have developed packages that offer a simple input mechanism, but these have met with resistance from the marketplace because they are not part of the Java standard. Others have suggested that a console-like input facility is a throwback to an out-of-date procedural programming style and that such techniques should be replaced by dialog input that fits the more modern, interactive style.

With the release of Java 5.0, console-style user input—for those who want it—is less of a problem. The new Scanner class in the java.util package makes it relatively easy to read input values from a stream using the following code:

 

Scanner sc = new Scanner(System.in);
int n = sc.nextInt();

Unlike the stream operations defined in the java.io package, the Scanner abstraction does not throw exceptions that the client code must catch, thereby simplifying the required code enormously.

A2. Conceptual difficulty of the graphics model

Ever since the technology has made it possible, many instructors have included graphical applications in their introductory programming courses because such applications generate so much excitement in students even as they illustrate important programming concepts. Although the Java APIs offer extensive graphical capabilities, it is often difficult for novices to master the Java graphics model [Bruce01, Martin98]. In a 1998 paper [Roberts98], Eric Roberts identified three problems in the Java graphics model that make it difficult to use for beginning students:

  1. Forgetful bitmaps. Under the Java graphics model, each component has the responsibility to respond to update events, which generate calls to paint (or paintComponent under Swing). Implementing those repainting methods requires students to maintain enough state information to regenerate the image. Designing the data structure to maintain this state is much more difficult than calling a set of methods to create a static display. This problem can be solved through a technique called double-buffering, in which the user’s program draws into an offscreen memory buffer that can be copied to the screen whenever an update event occurs.

  2. Statelessness of the graphics context. In Java, the graphics context preserves relatively little state from call to call, which forces programmers to maintain more state in their code. In particular, Java does not maintain the notion of a current point, which forces students to specify the endpoints of each line segment explicitly rather than chaining together a set of vector displacements.

  3. An unfamiliar definition of the coordinate system. Java’s standard coordinate system differs from traditional mathematical coordinates in three ways: (1) it uses integers rather than real numbers to specify points, (2) coordinate values depend on the device resolution, and (3) the axes are not arranged in the familiar Cartesian form. Each of these differences makes it more difficult for the student to use the graphics model.

A3. GUI components inappropriate for beginners

The standard interactor classes provided by the Java Swing library are often difficult for novices to use. To overcome this problem, several institutions that have adopted Java have developed new interactive toolkits to provide similar functionality in a form more easily understood by introductory students. The toolkits include the Java Power Tools collection developed at Northeastern [Raab00, Rasala00] and the simpleIO package developed by Ursula Wolz and Elliot Koffman [Wolz99]. The advantages of such a approach are illustrated in the following list of goals for the Java Power Tools package, which seeks to provide

A4. Inadequate support for event-driven code

Given that most computer science instructors are more familiar with such an approach, many institutions have continued to teach their introductory courses in a procedural style, even if they have adopted Java as the language of instruction. In fact, the Computing Curriculum 2001 report [ACM01] found that most courses we surveyed operated under a traditional procedural paradigm, even if they used an object-oriented language to do so. A few particularly forward-looking institutions were experimenting with alternative curriculum designs in which students are taught the object-oriented paradigm from the very beginning. Such strategies typically begin with simple objects that respond to messages generated either by asynchronous events or through interaction with other objects. Creating programs in this style gives students a much deeper perspective on the philosophy of object-oriented design.

Unfortunately, such approaches can be difficult to implement in standard Java because of the complexity of the event model and the difficulties involved in coding concurrent programs [Bergin98, Hartley98]. To get around these problems, some institutions—notably Williams [Bruce01] and MIT [Stein98]—have experimented with toolkits that support highly interactive, event-driven programs. To allow more institutions to use similar curricular strategies that emphasize an object-oriented approach, it will be useful to make this sort of toolkit more widely available.

The Java 5.0 release does include a new toolkit for concurrency based on earlier work by Doug Lea [Lea99]. While this new API will provide much better support for concurrency in Java, it is not clear to what extent this package will prove useful in the introductory course.



Final Report—July 31, 2006