CS61B, lecture #1 6/19/2000. Paul N. Hilfinger with modifications by M. Brudno A Little About Java - ------ ----- ---- You probably know Java as the language in which people write applets for the World Wide Web. Java, however, is much more powerful, and has much broader uses. Sun claims that "Java is a simple, object-oriented, distributed, interpreted, robust, secure, architecture-neutral, portable, high-performance, multi-threaded, and dynamic language," and while this characterization is arguable, Java is definetly a very nice language with which to teach Data Structures. The Java design was to start with C syntax and semantics. The next step was to carefully select a few features to include from C++ such as objects and exceptions. The idea here was to not add add features which are redundant, unsafe, messy, or complex. Then some new features were added: automated storage management, concurrency, and runtime error checking. The result was a language which is possibly a little slow and lacks some powerful capabilities of C/C++, is very easy to write in learn, allowing us to conentrate on the important stuff without getting lost in a syntactic jungle. Structure of a Java Program --------- -- - ---- ------- Any significant program in a modern programming language consists of a sequence of definitions of various terms. These definitions use each other and also use some set of primitive definitions supplied by the programming language and its environment (``environment'' in this sense is just a general term meaning ``organized collection of tools and pre-defined stuff.''). In Java, one defines ``classes,'' which are themselves collections of declarations of ``methods'' (functions), and of ``instance variables'' and ``class variables,'' which contain data values. To keep order, classes are further grouped into ``packages''---collections of classes. A program is a collection of classes, one of which is (somehow) designated as the ``main class.'' The effect of executing the program is looking for a method (function) called ``main'' in the main class and calling it. Here is a very simple program, consisting of a single class, Hello, containing a single method, main: public class Hello { static public void main (String[] args) { System.out.println("Hello, world! Did I hear you say \"" + args[0] + "\"?"); } } We put this program into a file named 'Hello.java', and compile it with the command % javac -g Hello.java (The `%' here denotes a command-line prompt). The program `javac' is the Java compiler. It produces a file called Hello.class, containing the translated program (the -g means ``produce debugging information''; more on that later). We can run the translated program like this: % java Hello Hi eliciting the response Hello, world! Did I hear you say "Hi"? The program `java' is the Java interpreter, which executes compiled Java programs. Let's take this program apart: * public class Hello { ... } This says that Hello is a class, and that it is "public", meaning that any other part of the program is allowed to refer to it by name. This is like what you would have written in CS61A as (define-class (Hello) ...) * static public void main (String[] args) { ... } This says that main is a function in class Hello. The "static" keyword means that it is an ordinary function (such as you find in C, Pascal, Scheme, and most other programming languages). As before, "public" keyword here means that any other part of the program is allowed to refer to this function. The "void" keyword tells what kind of value this function will return. Java, like Pascal and C, is `statically typed,' meaning that one is able to ascribe a single kind of value to every expression in the language (in particular to every named object and to the result returned by every function call). This is in contrast to Scheme, where one doesn't need to explicitly mention what kind of value is returned by a function. The "String[] args" says that the function "main" takes a single parameter (or "argument"), referred to in the body of main as "args". It also says that args is an array ("[]") of Strings. When the interpreter executes a program, it takes all the words on the command line following the name of the main class (in this case, everything after ``java Hello'') and turns it into an array (a sort of list, each of whose elements is numbered, starting at 0) of Strings, which are sequences of characters. This array then becomes the argument to the main program. The ... is the definition of the function. You Scheme programmers would have written this as (define (main args) ...) * System.out.println(...) `System' is the name of a standard, pre-defined class in Java. This class resides in a pre-defined package (see above) called `lang' which itself resides in a pre-defined package called `java'. It's full name is therefore `java.lang.System'. However, because it and other classes in the package java.lang are used so often, the designers of Java decreed that one may refer to it by its _simple name_. Inside the class System, there is a class variable called `out'. Class variables are like outer-level definitions in Scheme---as if one had written (define System.out some-initial-value) In this case, `some-initial-value' is an _instance_ of a class called java.io.PrintStream (the java.io is another of these pre- defined packages). More on instances later; for now, suffice it to say that one purpose of a class is to serve as a template for objects that are called instances of the class. An instance of PrintStream is like what in CS61A you might have created by (instantiate PrintStream) The class java.io.PrintStream defines a method called println that operates on PrintStreams. The notation `System.out.println(something)' is what one might more naturally write as println(System.out, something); ---that is, as a call to a two-parameter function. However, Java, like Smalltalk, Objective C, Sather, Eiffel, C++, and a host of other object-oriented languages, sometimes likes to treat the first parameter as something special. Go figure. In CS61A, you would have written this as (ask System.out 'println something) and println would have been defined in class PrintStream as (method (println arg) ...) One difference from the CS61A facilities, however, is that there are, in fact, a number of `println' methods defined in the class PrintStream. Which one is being referred to here depends on the type of the argument to System.out.println. In this case, the argument happens to be a String, and the effect of performing System.out.println on a String is to write its characters onto System.out, followed by an end-of-line. System.out happens to be connected to the `standard output' of the program---that is, the stuff that gets printed on your console. * "Hello, world! Did I hear you say \"" + args[0] + "\"?"); Those things surrounded in quotation marks ("") are String literals, which denote Strings consisting of the sequences of characters enclosed by the quotation marks (in the terminology of computer languages, `literal' refers to constants that ``mean literally what they say.'' For example, 3 is an integer literal.) To indicate that one of the characters in the string is a quotation mark, one uses the `escape sequence' \". As I said before, args is an array---an indexed sequence---of strings. The first string in this sequence is the 0th: denoted args[0]. Finally, when applied to Strings, "+" means "concatenate". That's the whole thing. But suppose now that I don't supply the argument "Hi" on the command line, so that args contains no elements? Let's try it: % java Hello java.lang.ArrayIndexOutOfBoundsException: 0 at Hello.main(Hello.java:5) The response is a message from the interpreter indicating that an `exception' of type java.lang.ArrayIndexOutOfBoundsException was `thrown' at line 5 of our program (where the args[0] is). This particular exception has a message attached to it: "0", telling us that the offending array index (the thing in the [...]) was 0, and that, because the array in question had no elements, there was no element number 0. Factorial --------- In Scheme: (define (factorial n) (if (<= n 1) (* n (factorial (- n 1))))) In Java: long factorial(int n) { if (n <= 1) return 1; return n * factorial(n-1); } An iterative version of Java using some shorthand: long factorial(int n) { long result = 1; for (int i = 1; i <= n; i++) result *= i; return result; }