2. Java as a Teaching Language
A good place to start is with the The Java Language: An Overview
[14] (previously titled
The Java Language: A White Paper), a well-known document from Sun
Microsystems that lists eleven properties of Java. Although this document
describes the significance of these properties from the standpoint of
commercial programming, it might as well have been addressing the academic
world, where they are just as important, if not more so. Let's review the
properties, considering the relevance of each one to the introductory
programming course.
2.1 Simple
Although Java resembles C++, it omits many of C++'s more confusing features,
including the ones most likely to cause problems for beginners: pointers,
operator overloading, multiple inheritance, and templates. Moreover, Java
lacks many of the automatic type conversions that C++ performs.
At the same time, Java adds an important feature that simplifies programming:
automatic garbage collection. Having the language handle storage management
gives Java a big edge in introductory classes over languages such as C and
C++, where releasing memory that's no longer needed requires programmer
intervention. Garbage collection not only makes programming easier but also
avoids the bugs caused by dangling pointers. In C++ programming, too much
effort is spent on problems of memory allocation and deallocation. As Bergin
[1] notes, ``some reports from industry
are that on large [C++] projects, half of the programming effort is spent
in getting memory management right.''
Overall, Java is a small language, closer in size to Pascal or C than Ada
or C++. Java's relatively small size is a powerful argument in its favor
as a teaching language. As one author puts it, ``Possibly the most
attractive feature [of Java] is the relative smallness of the language.''
[5]
2.2 Object-Oriented
The importance of introducing the object-oriented paradigm early in a
student's program of study is increasingly being recognized. However,
there's widespread disagreement over which object-oriented language to use.
C++ is the most popular object-oriented language used to teach introductory
programming, but it has plenty of critics. Some even argue that no existing
object-oriented language (prior to Java, at least) is really suitable for
beginners [6]. (This paper describes
desirable characteristics for a beginner's object-oriented language.
Although the paper predates the release of Java, the authors might just
as well have been describing Java.)
Java also supports object-oriented programming, but with significant
advantages over C++:
- Students must use objects. Only the primitive types are not objects.
There are no stand-alone functions; all functions must belong to a class.
- Objects are always allocated dynamically and manipulated through references,
thereby simplifying their semantics.
- Storage management is handled automatically, significantly reducing the
difficulty of writing many classes.
- Fancy features, like operator overloading and multiple inheritance, are
missing. Students have less to learn before writing useful classes, and
they can concentrate on learning the object paradigm rather than mastering
a host of esoteric details.
In its support for object-oriented programming, Java is closer to Smalltalk
than C++. Smalltalk is even more object-oriented than Java, and it makes a
good introductory language as well [17].
However, Smalltalk has a syntax that's difficult for beginners to grasp,
among other drawbacks [6].
2.3 Distributed
With the growing importance of networking in general and the Internet in
particular, students need experience in writing software that's
network-aware. Java is unique among major languages in its support for
networking, which includes classes for working with URLs and sockets.
Although most of Java's networking capabilities wouldn't be used in an
introductory course, some of the simpler ones could make excellent examples.
For example, Java makes it easy for programs to access specific URLs on the
Web, allowing students to gain a better understanding of how the Web works
as well as being able to write some rather interesting programs. Ambitious
instructors could use the more advanced networking features to illustrate
how programs cooperate over a network.
If Java is used in the second programming course as well as the first one,
its networking support would be more likely to come into play. At one
college, students use Java in the first two programming courses. When asked
what was the most surprising thing about using Java, the instructor
replied, ``For me, the way in which CS2 students so readily adapt to the
notion of building reactive, distributed programs on the internet, and how
this, as much or more so than the object-oriented aspects of Java
programming, so fundamentally governs their attitudes on what programming is
all about.'' [8]
2.4 Robust
A number of Java's properties are the result of making the language safe for
transmitting executable content over the Internet. These properties, as it
turns out, are often the same properties instructors look for in an
introductory language. As [14] puts it,
``Java puts a lot of emphasis on early checking for possible problems, later
dynamic (runtime) checking, and eliminating situations that are error
prone.'' This should be music to the ears of Pascal and Ada instructors
who have resisted switching to C or C++ because of their relatively weak
abilities to detect errors.
Here are some of the measures that Java uses to achieve robustness:
-
No pointers. Although Java uses pointers internally, no pointer operations
are made available to programmers. There are no pointer variables, arrays
can't be manipulated via pointers, and integers can't be converted into
pointers.
-
Garbage collection. Thanks to automatic garbage collection,
there's no chance of a program corrupting memory via a dangling pointer.
-
Strict type checking. Java's type checking is much stricter
than that in C or C++. In particular, casts are checked at both compile time
and run time. As a bonus, type checking is repeated at link time to detect
version errors.
-
Run-time error checking. Java performs a number of checks at
run time, including checking that array subscripts are within bounds.
2.5 Secure
In addition to being robust (resistant to programmer error), Java
programs are designed to be secure (safe against malicious attack).
Java's run-time system performs checks to make sure that programs transmitted
over a network have not been tampered with. The code produced by the Java
compiler is checked for validity, and the program is prevented from performing
unauthorized actions. For example, an applet that's been downloaded from a
Web page can't access files on the local computer. Moreover, the nature of
Java makes it hard to write viruses and other kinds of malicious programs.
A program that can't access memory locations via pointers will find it hard
to do much damage. Instructors who have been stung by viruses in student
programs will appreciate the security provided by Java.
2.6 Architecture-Neutral
The Java language is completely architecture-neutral. As a result, programs
written in Java will run on any platform that supports the Java run-time
system.
The significance of a multiplatform language like Java cannot be overstated.
Sun's Java Development Kit is available for a variety of platforms,
including Windows 95 and NT, Macintosh, and Sun Solaris, all of which are
widely used in education. Colleges can offer Java without having to worry
about whether their labs contain enough computers of the same type. Students
can easily transport programs from campus to home and vice-versa, even
though their home computers may be different from the ones on campus.
2.7 Portable
Java programs are not only architecture-neutral but portable as well. One
way in which Java achieves portability is by completely defining all aspects
of the language, leaving no decisions to the compiler writer. Consider the
issue of types. Most programming languages don't define the exact ranges of
types, allowing for variations based on the computer's architecture. Java,
on the other hand, completely defines the ranges and properties of all
types. Values of the int type are always signed 32-bit integers;
float values are stored in 32 bits using the IEEE 754
representation. That's a plus for instructors, who don't have to worry about
trying to explain to beginners why a program may not work if compiled with a
different compiler.
Other aspects of Java are portable as well. Java's libraries are designed
for complete portability. The Java system itself is portable. Sun's Java
compiler is written in Java itself; the run-time system is written in
Standard C.
2.8 Interpreted
Java is usually an interpreted language. A Java compiler translates a
program into bytecodes, which can then be executed by an interpreter.
Linking is done at run time, with code loaded dynamically by the run-time
system as needed. For students, this means that building a program is
simple: there's no linking step to perform. When one part of a program is
changed, only that part needs to be recompiled, and there's no linking step
to redo.
From the standpoint of the instructor, the fact that Java is interpreted has
two primary implications. One is that Java programs won't run at the same
speed as programs written in a compiled language such as Pascal, Ada, C,
or C++. For most student programs, however, the speed of execution is
irrelevant.
A more important implication of interpretation is that students will be able
to get excellent feedback when a program fails during execution. A C or C++
program that fails at run time generally doesn't provide any clue as to the
problem; students are forced to crank up the debugger. A Java program that
fails can print the call stack and describe the exception that caused the
program to fail. That information alone is often enough to pinpoint the
cause of the error, without the need to use a debugger. This behavior is
possible thanks to information about the source program that's embedded into
the bytecodes during compilation.
2.9 High-Performance
Programs written in interpreted, garbage-collected languages often don't
execute at high speed. In Java, however, the performance penalty isn't as
bad as in some languages. One reason for Java's superior performance is that
garbage collection is done by a separate low-priority thread. That way,
garbage collection takes place primarily when the program has nothing else
useful to do--while it's waiting for user input, say.
Greater speed can be achieved by translating Java's bytecodes into native
machine instructions. This can be done by translating the entire program to
native code prior to execution, or it can be done on the fly by a
``just-in-time'' (JIT) compiler. JIT compilation is becoming a standard
feature of commercial Java environments; both Borland C++ 5.0 (which
supports Java) and Microsoft J++ 1.0 provide JIT compilers. When translated
into native code, Java's performance ``is almost indistinguishable from
native C or C++'' [14]. Java's support for
translation to machine code is one of the features that gives it an edge
over Smalltalk, another interpreted, garbage-collected language.
2.10 Multithreaded
Unlike most major programming languages (with the notable exception of Ada),
Java has built-in support for multitasking. A Java program may create any
number of threads, which appear to execute in parallel.
For instructors, Java's support for threads provides a golden opportunity to
introduce students to the concept of concurrency, a topic that's already
important and will only become more so in the future, with multiprocessor
PCs soon to be commonplace. It is imperative that students become
comfortable with concurrency early in their studies. Java's model of
concurrency is simple enough that even beginners can use concurrency
effectively.
Instructors teaching concurrency often use Ada, one of the few mainstream
languages to provide built-in support for concurrency. However, Ada provides
no support for GUI interfaces, without which writing simple concurrent
programs is difficult. Ideally, a concurrent program should support multiple
input sources and multiple output destinations, to avoid problems of mutual
exclusion. Doing this in Ada is not trivial. Java's support for GUI
interfaces makes it a snap to write programs that illustrate concurrency.
Entering keyboard input into a concurrent program is tricky, because only
one task can read from the keyboard. With separate windows for tasks,
however, input is easy. Similarly, writing output to the screen becomes an
exercise in mutual exclusion in Ada; a Java program simply writes to
different windows.
Knowledge of threading isn't required to write Java programs, so instructors
who wish to skip it in a first class may easily do so.
2.11 Dynamic
Java is designed to accommodate the fast-paced, modern world of software
development, in which components of a system may change on a regular basis.
Java's run-time linking guarantees that a program always loads the most
recent version of its library modules. (That's good for students, who often
forget to relink and end up running older versions of their programs.)
It also reduces recompilation by making it possible to add methods and
instance variables to a library without having to recompile its clients.
Next section
Permission to make digital or hard copies of part or all of this work for
personal or classroom use is granted without fee provided that copies are
not made or distributed for profit or commercial advantage and that copies
bear this notice and the full citation on the first page. Copyrights for
components of this work owned by others than ACM must be honored.
Abstracting with credit is permitted. To copy otherwise, to republish,
to post on servers or to redistribute to lists, requires prior specific
permission and/or a fee.
© 1997 ACM