Sei sulla pagina 1di 96

Object Oriented Programming - Lecture Notes

Mehmet Gener c Istanbul Bilgi University Department of Computer Science

Contents
Preface 1 Introduction 1.1 Functional/declarative vs imperative programming 1.2 Strictly typed languages . . . . . . . . . . . . . . . 1.3 Object orientation . . . . . . . . . . . . . . . . . . 1.4 Compiled vs interpreted languages . . . . . . . . . 1.5 Resources . . . . . . . . . . . . . . . . . . . . . . . 1.6 Exercises . . . . . . . . . . . . . . . . . . . . . . . . ii 1 1 2 3 4 5 5

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

2 Introduction to imperative and strictly typed programming in Java with Processing 6 2.1 Iteration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2 A note about data types . . . . . . . . . . . . . . . . . . . . . 8 2.3 Variable scopes . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.4 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.5 Creating animations with Processing . . . . . . . . . . . . . . 9 2.6 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3 Data types, variables, expressions and arithmetic, arrays, and iteration 3.1 Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Operators, expressions, and arithmetic . . . . . . . . . . . . . 3.3 Arrays and iteration . . . . . . . . . . . . . . . . . . . . . . . 3.4 Variables and reference types . . . . . . . . . . . . . . . . . . 3.5 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11 11 12 13 15 16

4 Classes and Objects 17 4.1 Creating classes: types, objects, instances, and references . . . 18 4.1.1 Accessing state variables of an object: the . notation . 20 4.1.2 Using constructors . . . . . . . . . . . . . . . . . . . . 20 i

CONTENTS 4.1.3 Using instance methods . . . . . . . . . . . . . 4.1.4 Exercises . . . . . . . . . . . . . . . . . . . . . . Using class diagrams in class design . . . . . . . . . . . Using DrScheme/ProfessorJ for non-graphical exercises Garbage collection and object destructors . . . . . . . . Creating three dimensional animations in Processing . . . . . . . . . . . . . . . . . . . . . . . . .

ii 22 23 23 24 25 25 28 29 30 30 32 34 35 36 36 37 37 39 39 39 40 43 44 45 46 47 47 49 51 . . . . 53 53 54 54

4.2 4.3 4.4 4.5

5 Classes, types, and objects 5.1 Class members versus object members . . . . . . . . . . . . . 5.1.1 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Reection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Using Industrial Grade Java Environments 6.0.1 Why the static main() method? . . 6.1 Using Java libraries . . . . . . . . . . . . . . 6.2 Everpresent objects in JVM . . . . . . . . . 6.3 Interacting with the user . . . . . . . . . . . 6.4 Exercises . . . . . . . . . . . . . . . . . . . . 6.5 Handling errors in Java programs . . . . . . 6.6 Self documenting programs . . . . . . . . . . 6.6.1 Exercises . . . . . . . . . . . . . . . . 6.7 Proling Java processes . . . . . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

7 Sub-classing and Inheritence 7.0.1 A note about the types . . . . . . . . . . . . . . . . . . 7.1 Scopes, disambiguation, and overloading . . . . . . . . . . . . 7.1.1 Overloading and overriding methods, method signatures 7.2 Abstract classes and methods . . . . . . . . . . . . . . . . . . 7.2.1 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . 7.3 An example of extending JDK classes: Graphical user interfaces 7.3.1 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Interfaces 8.1 Multiple interfaces (or why interfaces are better than abstract classes) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2 Mixing the mechanisms . . . . . . . . . . . . . . . . . . . . . 8.2.1 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . 8.3 Example: Responsive GUI application . . . . . . . . . . . .

CONTENTS

iii

9 Encapsulation and data safety in classes 58 9.0.1 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . 59 9.1 Nested and anonymous classes . . . . . . . . . . . . . . . . . . 59 10 Implementing data structures 10.1 Self-references, mutual-references . . . . . . . . . . . . . . . . 10.1.1 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . 10.2 Variable size data: implementing mutable lists . . . . . . . . . 11 Object serialization and persistence 11.0.1 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1 Using Databases . . . . . . . . . . . . . . . . . . . . . . . . . 11.1.1 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . 61 61 63 64 69 71 71 74

12 Java packages 75 12.0.2 Distributing multi-le Java applications: jar archives . 81 A A guide for coding style A.1 Demarcation . . . . . . A.2 Organization . . . . . A.3 Explanation . . . . . . A.4 Explication . . . . . . A.5 Naming conventions . . Notes References Subject Index 83 83 85 86 87 88 89 89 89

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

Preface
These lecture notes are unnished work that is a collection of materials used in Object Oriented Programming (OOP) undergraduate courses given to second year students at Istanbul Bilgi Universitys Department of Computer Science. Target audience were students who have learned essential functional programming principles and practice using Scheme language. The OOP course aims to teach these students various aspects and practices of OOP using the Java language. Due to such positioning the course aims to rst introduce students to writing programs in an imperative and strictly typed language like java, then proceeds to object oriented paradigm. Through the way we introducing them to tools and practices usable in industrial applications, and underline relative strength and weaknesses of imperative/OOP for dierent elds of applications. The course syllabus for the actual courses these lecture notes are used for can be found at http://cs.bilgi.edu.tr/~mgencer/coursemat/OOPsyllabus. pdf which provides information on detailed objectives and administrative matter. These notes are provided as a standalone introductory level document on object oriented programming for anyone interested.

iv

Chapter 1 Introduction
The programming language, Java, which will be used for practicing concepts taught in this course shares some common features with other industrial grade programming technologies that are very popular today such as C/C++. The key features that distinguish these programming languages from those such as Scheme and Lisp are that (1) they are typed or strictly typed languages, (2) they are object oriented, (3) they are mostly used in imperative style programming, and (4) they are compiled rather than interpreted. Before we start o with full blown examples of Java programs we must explore these features.

1.1

Functional/declarative vs imperative programming

Introducing computer science to programming using a functional programming language like Scheme is gaining popularity among instructors, and well justied considering my experience with performance of those students in later subjects during their education. Functional programming falls under a generic category of approach which is called the declarative approach in programming. In this style of programming, it is more natural for the programmer to code a computation into a program, once it is mathematically well established. Consider, for example, the problem of computing Fibonacci numbers1 . The series of Fibonacci numbers can be expressed as follows: Fn = n if n = 0 or n = 1 Fn1 + Fn2 if n > 1

CHAPTER 1. INTRODUCTION

With the above mathematical denition in hand, it is quite straightforward to express the computation as a Scheme program as follows: Example: Fibonacci numbers in Scheme (define (fibo n) (cond [(<= n 1) n] [else (+ (fibo (- n 1)) (fibo (- n 2)))])) This approach is labeled as declarative programming since the programmer expresses what needs to be computed (usually in a recursive manner as in the above example), rather than how to compute it (the imperative way). As a result functional/declarative programs are easier to check for correctness. While ease of code expression is and important advantage, especially in early stages of programming education, there are certain motivations to seek other approaches. First is the fact that achieving computational eciency may not be possible with the most natural formulation of a computation when expressed as a declarative program. The Fibonacci numbers example above is one example of inecient code (see Exercise 1). While it is possible to write an ecient program using declarative style and recursive algorithms (see Exercise 2), the mathematical formulation of this new program will no longer be trivial as the rst one, hence undermining the advantage of declarative programming in cases like this. A second motivation for imperative programming is the fact that it is how computer hardware actually works. CPUs (Central Processing Units) simply follow a series of instructions. Languages such as C oer the advantage of resembling more closely the underlying system they intend to control. Programming languages like Java and C/C++ are not imperative themselves. However, the programming practice of using these languages have been mostly in imperative style and the languages themselves has many facilities that are targeted for such use, such as statements for iterations.

1.2

Strictly typed languages

In the above example of Fibonacci program theres no indication that the function parameter must be an integer, nor is its return value. Therefore the correct functioning of the system relies on passing of correct values to the function. Many other languages are more sensitive to types of function arguments and return values, and called strictly typed languages for this

CHAPTER 1. INTRODUCTION

reason1 . The following function denition is an example implementation of recursive -and inecient- Fibonacci program in a strictly typed language: Example: Fibonacci numbers in Java/C int fibo(int n) { if (n<=1) return 1; else return fibo(n-1)+fibo(n-2); } The above code can pass as a function denition in both C and Java languages (as the latter was inspired by from the former heavily and uses similar syntax). There are several dierences compared to Scheme program: Functions are called with a syntax like bo(5), not (bo 5). cond is replaced by if. Inx notation is preferred to prex notation. i.e. n-1, not (- n 1). Parantheses in Scheme is replaced by curly brackets. Each program statement ends with a ;. Instead of Scheme comments starting with ;, there are long (multiline) comments between /* and */, and single line comments starting with //. Most importantly both the function name and parameter is preceeded with int which indicates that they are of type integer. Despite the syntactic dierences the function outline resembles that of the Scheme version.

1.3

Object orientation

Traditional computer programs look much like the computer itself. They are composed of functions, which take some inputs and produce an output; much like basic circuit elements like AND,OR gates. The larger software system is an interconnection of inputs and outputs of such elements.
Some languages like C are not as strict concerning types. However, this is generally a dangerous preference and only remains to allow low level hacking of computer systems.
1

CHAPTER 1. INTRODUCTION

While this aproach works for smaller systems, it caused many problems as the applications of computer programs grow in variety and scale (See (?) for a good reading on these issues). Just like circuits, failure of one element has rendered the whole system malfunction. OOP came out as a practical solution to these problems. OOP is based on the concept of object , which correspond to an actual entity in the problem one tries to program for. The object in OOP encapsulates all data of a certain type of object and functions applied to that data in programming units called classes. Such way of conceptually collecting data and functions related to that data is found to reduce programming errors in large software systems, in addition to being easier to design as things correspond to real entities. Therefore in order to apply OOP, one needs programming languages that support such mechanisms. Most modern programming languages today support objects in one way or another. Various software tools are referred to in the incremental treatment of the matter in this document.

1.4

Compiled vs interpreted languages

Some popular programming languages like Scheme, Lisp, Python, PHP, and Perl are all interpreted languages. One needs a special program called interpreter which runs the program written by the programmer. This has the advantage that if one has an interpreter for dierent systems (e.g. Linux, Python, a cell phone) the same program can be used without any changes. On the other hand this approach has some disadvantages. The interpreter program must spend a certain time parsing the program before it can be run (hence the word interpret). This brings a certain overhead to the system and interpreted programming languages are generally slower than compiled languages. In compiled languages the program is rst passed through a special program called the compiler which translates it to machine code which can be directly executed by the hardware (i.e. the CPU). For example we cannot use an interpreted language to write an OS(operating system), because the OS is the rst program to run on the hardware, hence there cannot be an interpreter already available there. Furthermore, compilers can have certain advantages in terms of optimizing the outcome with respect to specic features of the target hardware. Finally, compiled languages are preferred for commercial programs since the original program cannot be recovered by looking at the machine code which is delivered to the customers. Therefore an organization or person who seeks prot from a computer program can keep the original code hidden as a private asset. Java is somewhat distinct in the sense that it is both compiled and inter-

CHAPTER 1. INTRODUCTION

preted. The Java compiler produces machine code for execution on not a specic hardware but something called Java Virtual Machine (JVM). Dierent JVMs of varying capabilities are available for regular PCs, larger computers, cell phones, or chips used in credit cards. In this way Java retains the dual advantages of portability and performance.

1.5

Resources

There are various Java programming and object oriented programming books around. However, this lecture notes are intended to go with a general purpose Java reference (such as ?) in addition to other material referenced in the text.

1.6

Exercises

1. Find the complexity, O(), of the Fibonacci program. 2. Write a Scheme program to compute Fibonacci numbers eciently.

Chapter 2 Introduction to imperative and strictly typed programming in Java with Processing
Before we attempt writing Java programs for inductrial grade Java programming environments, in this chapter we will start by using Processing (see htt://www.processing.org) to write simple programs that produce visual output. You can install Processing by downloading it from its website. When it is run you will see a screen where you can type your program, much similar to the way DrScheme works. Processing programs are Java programs, but Processing allow us to postpone some cumbersome aspects of industrial grade java environments and instead focus on imperative style programming in a strictly typed language. The Processing environment also have the advantage of having good quality reference and tutorial documentation in addition to examples. In the screen of Processing system enter your rst program as follows: Example: A rst Processing program /*Program to draw two lines of different thichnesses*/ void draw() { strokeWeight(1); //set line thickness line(0,0,50,100);// draw a line, eg. line(x1,y1,x2,y2) strokeWeight(5); line(50,100,100,50); } The special function name draw is used by the entry point to drawing by the Processing system. Note that the return type of this function is void, ie. 6

CHAPTER 2. INTRODUCTION TO IMPERATIVE AND STRICTLY TYPED PROGRAMMIN it does not return anything! This is typical of imperative style programming that the function is intended for its side eect, not its return value. What is drawn by the function remains on the screen (and memory of the Processing system) but no return value is meaningful in this case. The remainder of lines starting with a //, in addition to all text between /* and */ are comments in the Java program. It is possible to write Processing/Java programs using recursion. The following example draws a simple fractal shape: Example: Recursive pattern void draw() { drawRecursive(0,0,0,90); } void drawRecursive(float x, float y, float angle, float length) { if (length<=5) //stop drawing return; //return from function, with nothing since return type is void else{ float x2; float y2; x2=x+length*cos(angle); y2=y+length*sin(angle); line(x,y,x2,y2); drawRecursive(x2,y2,angle+PI/2,length*0.9); } } The above example demonstrates declaration of variables (e.g. oat x2) and assignment of values to variables (using = operator), in addition to using some trigonometric functions available in Processing. It also demonstrates use of conditional execution (the if .. else statement). In this program the sequence of statements in the drawRecursive() function is executed one after the other. This is why such programs are called imperative because they impose how and through which steps a task must be executed, contrary to the Scheme Fibonacci program before.

2.1

Iteration

The contrast between declarative and imperative programming becomes more striking if one uses iteration facilities to replace recursive calls. Following is a program to draw a similar fractal:

CHAPTER 2. INTRODUCTION TO IMPERATIVE AND STRICTLY TYPED PROGRAMMIN Example: Using iteration void draw() { drawIterative(0,0,0,90); } void drawIterative(float x, float y, float angle, float length) { float x1=x; float y1=y; float currentAngle=angle; float currentLength=length; while (currentLength>=5) { float x2=x1+currentLength*cos(currentAngle); float y2=y1+currentLength*sin(currentAngle); line(x1,y1,x2,y2); currentAngle=currentAngle+PI/2; currentLength=currentLength*0.9; x1=x2; y1=y2; } } The program uses the while statement which keeps executing the code (i.e. loops) in its brackets as far as the condition in the parenthesis is satised. In this example the importance of side eects for the working of the program are more apparent. The program relies on the fact that previous drawing point, angle and line segment length are stored in certain variables.

2.2

A note about data types

So far we have used two data types in Java: void and oat. There are various other data types such as double, long, boolean, String, etc. You are recommended to consult a reference documentation whenever necessary. In the future chapters we will have a closer look into data types.

2.3

Variable scopes

Note that among several variables declared in our iterative program some are inside the brackets that belong to the while statement. In Java variables continue to exists and keep whatever value you store in them until their

CHAPTER 2. INTRODUCTION TO IMPERATIVE AND STRICTLY TYPED PROGRAMMIN scope vanishes/exits, and the scope is essentially determined by the enclosing brackets. For example if there were any other statements after the while statement, it would not be possible to use x2 or y2 in those statements because their scope has been exited and they have been sent to trash by the Java system. On the other hand variables x1 and x2 can be used in the scope of the while loop in addition to the drawIterative() function, because their scope (the brackets of the function) contains the scope of while loop.

2.4

Exercises

E-1 Write a Processing program to draw a Koch snowake (search Google for this simple pattern). E-2 Write a Processing program to draw a tree using a fractal approximation.

2.5

Creating animations with Processing

What Processing system actually does is calling the draw() function you write repetitively. Processing rst calls a function named setup(), if available, and then calls the draw() function at a certain frequency. Let us write a Processing program which declares a setup() function to setup screen size and animation rate, in addition to using global scope variables: Example: Animated random lines float x=0; float y=0; void setup() { size(500,700); frameRate(5); } void draw() { //background(255); float tmpx=x+random(10); float tmpy=y+random(10); line(x,y,tmpx,tmpy); x=tmpx;

CHAPTER 2. INTRODUCTION TO IMPERATIVE AND STRICTLY TYPED PROGRAMMIN y=tmpy; } In the above program the variables, x and y, are at the global scope, wheras tmpx and tmpy are within the scope of draw() function.

2.6

Exercises

E-3 Write a Processing program which animates a growing circle. E-4 Write a Processing program to draw an analog clock on the screen. You can use hour(), minute(), and second() functions in Processing to learn the time. E-5 Write a Processing program to draw a fractal tree with random variations for more realistic results.

Chapter 3 Data types, variables, expressions and arithmetic, arrays, and iteration
As Java is a typed language, one needs to make informed use of data types and know related operations, as dierent from programming in a language like Scheme where types are not explicit (although they exist). In this chapter we will discover essential data types rst, then learn how to create and use lists (so called arrays). An important technique in using arrays is iteration, which is a common and practical replacement for recursion when the number of repetitions are known beforehand. WE have already dened and used some variables. Java uses two kinds of variables where the dierence is somewhat hidden from the programmer: primitive and reference type variables. WE will also explore the dierence, which is an important topic you may encounter when using other programming languages.

3.1

Data types

An important motivation behind the use of types (in addition to type checking for programming errors) is to use memory eciently. For this reason Java has several data types that are used when creating variables or declaring function parameters and return types. We will rst list the data types which are called primitive data types in Java. : int: A 32-bit signed integer. This is the common choice for storing integers unless theres a reason not to do so.

11

CHAPTER 3. DATA TYPES, VARIABLES, EXPRESSIONS AND ARITHMETIC, ARRAYS, A byte: An 8-bit signed integer. short: A 16-bit signed integer. long: A 64-bit signed integer. oat: A 32-bit oating point real number. Although this precision may be sucient for most purposes, you must consider using other types for further precision. double: A 64-bit oating point real number. boolean: A variable to store one of two values: true and false. Its size in terms of bits is not specied in Java specications. char: A single 16-bit Unicode character. Please note that all primitive data type names start with a small case letter. This is an important convenience you need to remember to deal with the issues of reference type which we will cover later. Declaring and using a primitive data type is quite straightforward. For example: int n1; int n_2; n1 = 1; n_2 = 25; A variable name must start with a letter and can contain letters, digits, and the underscore in its name. Other than these syntactic rules there are certain conventions in programming profession you should consider following. These are covered in Appendix A.

3.2

Operators, expressions, and arithmetic

It is possible to declare multiple variables of the same type on a single line or assign a value during declaration as follows: int n1=5; float x1,x2=6,x3=7; A variable can be assigned to the value of another variable or to result of an arithmetic expression:

CHAPTER 3. DATA TYPES, VARIABLES, EXPRESSIONS AND ARITHMETIC, ARRAYS, A int n1=5; int n2=n1/2; float x1=5.1; float x2=(x1/2+1)/5; In the above example note that the value 5/2 is not an integer. In such cases the result is trucated. In certain cases you may want to cast type of a value to something else using the new type in parenthesis. For example: float x=5.1; int n= (int)x/2; In addition to arithmetic operator (+-/*), there is also a modulo operator (%) which evaluates to remainder. Apart from numeric expressions, logical expressions can be constructed (for example in if statements) as in the following example: if if if if ( ( ( ( (x>5) && (x<=10) (x<5) || !(x>10) x%2 == 0) //true x%3 != 0) //true

) //true if x is greater than 5 AND less than or equal to ) // true if x is greater than 5 OR not greater than 10 if x is even if x module 3 is not equal to zero

3.3

Arrays and iteration

A consequence of the fact that Java is strictly typed and tries to optimize memory usage is that lists in Java are also restricted in their size. If we want to use a storage for many numbers (or other type of things) we must dene it to be of certain size. Such immutable, zed size lists are called arrays in Java (and in other strictly typed languages). Following syntax demonstrates how an array to contain ten integer values is created and accessed: int[] array; array=new int[10]; array[0]=1; .. array[9]=10; As seen in the example, arrays are indexed started from 0, i.e the rst element of the array is at position 0. An arrays length can be learned by appending .length to its name, e.g. array.length evaluates to 10 in the above example. Arrays of more than one dimension can be dened to store matrices as follows:

CHAPTER 3. DATA TYPES, VARIABLES, EXPRESSIONS AND ARITHMETIC, ARRAYS, A int[][] matrix=new int[5][10]; matrix[0][0]=1; ... matrix[4][9]=50; The size of such arrays are referenced similarly: e.g. matrix[0].length is 10, whereas matrix.length is 5. In other words each of matrix[i] is actually an array of length 10. As a result following assignment is valid: int[] row=matrix[0]; When using Scheme, you are accustomed to using recursive functions to span a list of values. For example by recursing into tail of a list to nd the maximum value in a list. Although the same is possible in Java, a convenient mechanism, called iteration, is commonly used to span a list whose size is know (which is commonly the case). This is particularly true for arrays. Following is an example function which returns the maximum of numbers in an integer array (note: array.length returns the size of array): /* * A function to find maximum of integers in an array */ int max(int[] array) { int max=array[0]; for(int i=1; i<array.length; i=i+1) { if (array[i]>max) max=array[i]; } return max; } The so called for loop syntax is as follows: for (initialization; control; increment) BODY The initialization is done rst. Then if the control expression is validated the BODY is executed. At the end increment part is done and control expression is checked again. This loop continues until control expression is not valid anymore. The BODY part of a for loop can be a single command as in the above example, or a group of commands enclosed within brackets { and }. Although brackets are unnecessary for a single command, it nevertheless increases readability of your programs and hence recommended.

CHAPTER 3. DATA TYPES, VARIABLES, EXPRESSIONS AND ARITHMETIC, ARRAYS, A

3.4

Variables and reference types

A second group of types in Java are so called Reference types. These are closely related to classes and object as we will explore in the further chapters. A common reference type is String, which is used for storing pieces of text: String message = "Hello mer!"; O System.out.println(message); //prints the string to terminal output The important dierence between reference and primitive data types relates to assignment and comparison operations. The key to understanding the dierence is that reference type variables are addresses (or so called references) of the actual value stored in memory, whereas primitive type variables store the actual value. For example: int n1,n2; n1=1; n2=n1; n1=2; When the second statement above is executed the value of n1 is copied into n2. After the third statement the value of n1 is set to 2, however the value of n2 remains the same and not aected. However when a similar thing is done with a reference type like String: String s1="abcdef"; String s2=s1; s1="fedcba"; After the above statements are executed you will nd that the values of both s1 and s2 are the same (e.g. try printing them as above). The reason is that s1 and s2 are just two dierent names for the same variable in the memory. The assignment operator in the second statement above copies the address/reference of the rst one to the second, not its value. You will nd a similar result for all reference type variables in Java (such types all start with a capital letter). For the same reason the following comparison will not yield to a true value: String s1="abc"; String s2="abc"; if (s1=s2) // evaluates to false, because what is // compared is the references, not values We will learn how to compare strings after exploring classes, objects, and their methods.

CHAPTER 3. DATA TYPES, VARIABLES, EXPRESSIONS AND ARITHMETIC, ARRAYS, A

3.5

Exercises

E-1 Write a Processing program which animates 10 lled circles of dierent color, each of which are centered on a random position, starts from a diameter of 10, grows into diameter of 100 as they are drawn repetitively, then returns to diameter 10 again. E-2 Write a Processing program to draw the plot of a function, for example f (x) = 20 + 2x x2 /10 + x3 /100. E-3 Write a Processing program to draw a Fibonacci spiral or Fibonacci tiling. E-4 Write a Processing program which animates a growing fractal tree.

Chapter 4 Classes and Objects


Consider an example problem to solve in Processing: We want to animate a group of moving colored balls (i.e. circles in two dimensions for simplicity). Each ball has a dierent color, starting position and speed. In order to solve this problem one will need to store colors, positions, and speeds of balls in three dierent lists (in the same order so that information about a ball can be reliably identied). After drawing balls in their current position in each animation frame, we will need to modify their positions according to their speed. Following is a solution of the problem using techniques we have learned so far: Example: Growing balls problem int numberOfCircles=10; int sizeX=500, sizeY=700; color[] colors=new color[numberOfCircles]; float[] posx=new float[numberOfCircles]; float[] posy=new float[numberOfCircles]; float[] radius=new float[numberOfCircles]; void setup() { size(sizeX,sizeY); for(int i=0;i<numberOfCircles;i=i+1) { colors[i]=color(random(255)); posx[i]=random(sizeX); posy[i]=random(sizeY); radius[i]=10; } } 17

CHAPTER 4. CLASSES AND OBJECTS

18

void draw() { background(255); //white for(int i=0;i<numberOfCircles;i=i+1) { fill(colors[i]); ellipse(posx[i], posy[i], radius[i]*2, radius[i]*2); radius[i]=radius[i]+1; if (radius[i]>100) radius[i]=10; } } The solution looks ne and works, although it is not very easy to read, since the data for balls and operations on the data are dened is dierent places. If one wants to make the circles start from a dierent radius, or change the growth threashold, one can see how the above approach becames less readable (and writeable!).

4.1

Creating classes: types, objects, instances, and references

In OOP terminology objects are concrete examples of the class of things they belong. The motivation for using classes and object oriented programming has been to keep the data about an object and operations on that data close to one another. A class consists of (1) state variables that dene a particular object (instance of the class), and (2) the behavior of the object expressed as methods (functions in a class) next to state variables. Now we will start progressively dening our rst class to represent a growing ball in our problem. First we dene t he class with state variables only: class Ball { float positionX; float positionY; float radius; color ballColor; } The class denition collects properties of a ball (its position in two dimensional display, its radius, and color). You must remember that having a class does not mean that we have any objects. Dening a class in our programs

CHAPTER 4. CLASSES AND OBJECTS

19

means creating a new variable type (which is similar to int, or oat). Creating objects mean that we need to create instances of the class. An instance is a particular ball, not the general concept of ball, which has its particular values of the state variables. Creating objects (which is also called as instantiating a class) is somewhat dierent from creating variables of type int or oat. Following is an example of dening an object of a particular class type, and instantiating it: Ball ball; ball=new Ball(); The rst line above denes a new variable of type Ball. However it is dierent from dening a variable of type int. For int and other primitive types we can start using the variable (e.g. assigning a value to it) immediately after dening the variable. On the contrary, for objects one needs to create an instance of the class using new ClassName() as we have seen in the above example. This is due to the fact that objects are reference variables (like Strings) and are dierent from primitive types. For example consider the Java statements below below: Ball ball1,ball2; ball1 = new Ball(); ball2= ball1; In this example we have dened two variables of type Ball (in the rst line), but we have created only one object (in the second line). The second variable is assigned to the value of rst one (in the third line), but this assignment does not create a copy of the object, as it does for int or oat (or all primitive types). Instead it copies the reference to the object. As a consequence ball1 and ball2 are just two names for the same object in Javas memory. You must remember this distinction between primitive and reference types when programming in Java. As with primitive types, one can create arrays to store multiple objects. With our growing balls problem we can create the ten balls we need as in the following Processing program: class Ball { ... } Ball[] balls=new Ball[10]; void setup() {

CHAPTER 4. CLASSES AND OBJECTS for (int i=0; i<balls.length; i=i+1) { balls[i] = new Ball(); } }

20

4.1.1

Accessing state variables of an object: the . notation

Note in the above example that the state variables of the Ball object, ball1, has not been assigned any values. Variables of an object can be accessed using a special notation as in the following example: Ball ball; ball=new Ball(); ball.positionX=120; ball.positionY=ball.positionX; In our particualar example of the growing balls problem, we will need to assign initial values to each ball as follows: class Ball { ... } Ball[] balls=new Ball[10]; void setup() { for (int i=0; i<balls.length; i=i+1) { balls[i] = new Ball(); balls[i].positionX = random(500); balls[i].positionY = random(700); ... } }

4.1.2

Using constructors

As we have mentioned earlier, the key advantage of using classes and objects is to keep objects state variables and actions that pertain to these variables close to one another. Therefore the above example of initializing a Balls state variables is inadequate. In all object oriented languages it is possible to dene a special method called constructor which is used for initializing

CHAPTER 4. CLASSES AND OBJECTS

21

state variables. Constructor method must have the same name with the class, and is dierent from other Java functions in one sense that they do not have a return type. If a class has a constructor then the cosntructor method is executed automatically when an instance of the class is created using a statement like new ClassName(). In our particular example our constructor will need to know the size of the display so that ball position can be selected randomly within the screen. The modied class denition will look like the following: class Ball { float positionX; float positionY; float radius; color ballColor; Ball(int screenSizeX, int screenSizeY) { positionX=random(screenSizeX); positionY=random(screenSizeY); radius=10; ballColor=color(random(255),random(255),random(255)); } } Now if we want to create objects of this class, we will need to provide the required parameters during its instantiation, as follows: Ball ball=new Ball(500,700); With the latest version of our class, it is possible to write parts of the Processing program in a more simple and understandable way: class Ball { ... } Ball[] balls=new Ball[10]; void setup() { for (int i=0; i<balls.length; i=i+1) { balls[i] = new Ball(sizeX, sizeY); } }

CHAPTER 4. CLASSES AND OBJECTS

22

4.1.3

Using instance methods

We are only halfway through our denition of the Ball class. Unless the class have methods to control its behavior (ie. growing), it is incomplete. Class methods are function dened inside the scope of the class. They are like any other function in the sense that they have a return type and a parameter list. The only dierence is that since they are in the same scope with state variables of the object, these variables are accessible from the instance methods. Similarly the methods can access one another as they are in the same scope. Following is a complete version of our Ball class: class Ball { float positionX; float positionY; float radius; color ballColor; Ball(int screenSizeX, int screenSizeY) { positionX=random(screenSizeX); positionY=random(screenSizeY); radius=10; ballColor=color(random(255),random(255),random(255)); } void growAndPaint() { radius=radius+1; if (radius>100) radius=10; fill(ballColor); ellipse(positionX, positionY, radius*2, radius*2); } float area() { return PI*radius*radius; } } Note that we have added a class method to compute area of the Ball as an example of methods with return type, although it was not necessary for our particualr problem in hand. With this class denition in hand, our Processing program becomes much simpler and understandable:

CHAPTER 4. CLASSES AND OBJECTS class Ball { ... } Ball[] balls=new Ball[10]; void setup() { size(sizeX, sizeY); for (int i=0; i<balls.length; i=i+1) { balls[i] = new Ball(sizeX, sizeY); } } void draw() { background(255); for (int i=0; i<balls.length; i=i+1) { balls[i].growAndPaint(); } }

23

4.1.4

Exercises

E-1 Write a Processing program which animates several rectangles (their number is random between 5 and 15), of random position and color, which grow/shrink in width/height alternatively. E-2 Write a Processing program which animates moving balls, which start with random positions, radius, and speed, then move around the screen and bounce from the sides. E-3 Write a class to represent a complex number. The class must have a constructor method, and a method to compute magnitude (or so called absolute value) of the complex number. Assume that a method named sqrt() is available for taking square root of a number.

4.2

Using class diagrams in class design

The real potential of using objects in large scale software applications comes from the fact that objects in OOP correspond to real objects, and their interaction resemble actual interaction of entities in the system, rather than

CHAPTER 4. CLASSES AND OBJECTS

24

a clockwork modeling of reality that functional programming dictates (which is actually useful in small scale). This potential can be turned to actual advantage if OOP mechanisms are used within object oriented design (OOD) principles. The key element in design is deciding what properties and behavior of objects in a system will be like before actually writing the code for them. This practice provides what contracts do in PLT style Scheme programming. A common practice in object oriented design is starting o with so called class diagrams. Following is an example class diagram for what is expected to be a representation of Complex numbers: ---------------------------------------| Complex | ---------------------------------------| float real | | float imaginary | |--------------------------------------| Complex(float real, float imaginary) | | float magnitude() | | float getReal() | | float getImag() | ---------------------------------------The class diagram is a very concise summary of properties and methods of the class. Now if we want to write a method to multiply two complex numbers we know how to access its properties, before even the class is actually coded! This is an important advantage in industrial software development, because once it is decided how several classes will allow access to their methods and properties to create a useful system, dierent programmers can take each class and implement them. The collection of class diagrams provide a conceptual guide for those involved in creating the software system.

4.3

Using DrScheme/ProfessorJ for non-graphical exercises

Processing system is useful for graphical exercises, but is limiting for other types of programming. DrScheme program, to which students may be familiar from Scheme programming, has recently released with facilities to use it for Java programming. This extension called ProfessorJ takes us one step closer to using industrial grade Java environments.

CHAPTER 4. CLASSES AND OBJECTS

25

After running DrScheme, choose Java+dynamic as the language of study. Then in the DrSchemes main area you can enter your class denition. The console below the main area can be used to create instances of your class, and then to invoke its methods for testing. For the purposes of this course, we will not cover the testing facilities for Java programs. Try using DrScheme for solving the Complex number implementation exercise above.

4.4

Garbage collection and object destructors

Notice that we have not done anything to destroy objects we have created. When there is no reference available for an object or when its scope is destroyed, the Java garbage collector takes care of cleaning them. For example the code below: Circle c1=new Circle(100); c1=new Circle(200); leaves the rst circle inaccessible. Java keeps track of the references to objects, and takes care of cleaning the memory for objects which theres no way of referencing them again. In general we have no control over when or how often the garbage collection takes place. This have some consequences for real time programming using Java, but in general it is of no concern to programmers except such cases where instantenous performance is critical. When an object is destroyed by the garbage collector, the instance method called nalize(), if available, is called. This method is called the destructor, as it is the opposite of constructor.

4.5

Creating three dimensional animations in Processing

3D animation is an advanced topic in Processing. Nevertheless we provide a small example of it below, which uses a modied version of the Ball class and setup() function. Pleas enote that a library is necessary to use 3d drawing (see following chapters for importing libraries). Furthermore one needs to turn on the lights and use trandformations for 3D drawing. Please refer to Processing reference documentation to explore the 3D drawing facilities further. The key elements of drawing can be simplied as follows:

CHAPTER 4. CLASSES AND OBJECTS

26

It is easier to draw 3D shapes as if one draws them at the center of coordinate axes. For this reason one needs to transform the coordinate systems as desired. This consists of pushMatrix() and transform() operations. Once a 3D shape (e.g. sphere) is drawn, one can resume the coordinate system using popMatrix(). Ligths needs to be reset at every drawing, thus the lights() command must be placed in the draw() function. Following program draws growing spheres at random locations in the 3D space, uses default ambient lighting. import processing.opengl.*; class Ball { float positionX; float positionY; float positionZ; float radius; color ballColor; Ball(int screenSizeX, int screenSizeY, int screenSizeZ) { positionX=random(screenSizeX); positionY=random(screenSizeY); positionZ=random(screenSizeZ); radius=10; ballColor=color(random(255),random(255),random(255)); } void growAndPaint() { radius=radius+1; if (radius>100) radius=10; fill(ballColor); pushMatrix(); translate(positionX, positionY,positionZ); //ellipse(positionX, positionY, radius*2, radius*2); sphere(radius*2); popMatrix(); } float area() {

CHAPTER 4. CLASSES AND OBJECTS return PI*radius*radius; } } int sizeX=500, sizeY=700, sizeZ=500; Ball[] balls=new Ball[10]; void setup() { size(sizeX, sizeY,P3D); for (int i=0; i<balls.length; i=i+1) { balls[i] = new Ball(sizeX, sizeY,sizeZ); } } void draw() { background(255); lights(); for (int i=0; i<balls.length; i=i+1) { balls[i].growAndPaint(); } }

27

Chapter 5 Classes, types, and objects


You may have already noticed that variables which are objects (class instances) are dened similar to primitive type variables. For example: int x=2; Ball b=new Ball(); Also remember that the two variables are dierent: the rst is a primitive type variable which holds the value we assign to it, whereas the second is a reference type variable which holds the reference of the class instance. Despite these dierences the declaration syntax demonstrates that the new class we have dened, Ball, becomes a data type in Java. The new variable, b, in the above example is of this new type. Therefore, creating classes in Java means adding new data types to the language. The types are important in a strictly typed language like Java, because a variable of certain type can be assigned a value of the same type only. For example the following statement will cause an error in Java: Ball b=3; if ("abc">4) ... Because we are trying to assign an integer value to a variable of type Ball, or compare a string to a number! Java is quite strict about matching types in assignment or comparison operations. Nevertheless, it will allow automatic conversion between numeric types (e.g. from oat to int) in most cases. What is more interesting when using classes is that a class itself is a variable, of type class! Remember that a class denition starts as class Ball .... This has important consequences when programming in Java, because one must learn the dierence between a class (which is an entity of type class), and its instances (which are of type the class itself). Therefore a 28

CHAPTER 5. CLASSES, TYPES, AND OBJECTS

29

class is an entity of type class, but it is special in the sense that it creates a new type in Java. More important in this matter is that one must learn to dierentiate things which belong to a class, and things which belong to instances. This is perhaps one of the most stumbling points for students learning Java.

5.1

Class members versus object members

So far we have only used instances of classes. Therefore classes provided as a template for creating objects. However Java provides certain mechanisms for classes to have variables of methods of their own. This is done to save memory or speed up method invocation. For example consider a class to represent Circles, and to provide methods to compute its area and circumference. class Circle { double radius; double PI=3.14; Circle(double radius) { this.radius=radius; } double area() { return PI*radius*radius; } } With the above code, a copy of PI constant will be stored in computer memory for each instance of the class. Instead of doing so, we can dene the PI variable as a class variable using static keyword : public static double PI=3.14; This reduces the amount of memory to store variables by 50%! The static members of a class can be accessed without creating an object instance from class: eg. just Circle.PI. In some cases, the static mechanism can be used for methods also. For example if we want to implement a group of functions to operate on natural numbers: class NaturalNumberMethods { static int factorial(int n) { if (n<=1) return 1; else

CHAPTER 5. CLASSES, TYPES, AND OBJECTS return n*factorial(n-1); } static int fibonacci(int n) {...} }

30

Note that the class has no constructor, because it will neve be instantiated! It is just used as a container of methods and has no object specic state. Therefore the methods are accessed directly via classes: eg. NaturalNumberMethods.factorial(5). You must keep in mind that although static and non-static members are mixed in the class code, they are worlds apart. Static methods cannot reference object variables or use this keyword. For example if we opt to make area() method of the Circle class above as static, it would not work, since it references the object variable radius. Mixing static and non-static methods is rather counter-intuitive in object orientation (unlike rare cases as in the example above with static PI variable), although it is syntactically possible.

5.1.1

Exercises

E-4 Create a class which has collection of methods for complex number arithmetic, in addition to being able to represent a complex number. The class must have methods for addition, substraction, and multiplication of complex numbers. Note that each of these methods consume two arguments of type Complex (e.g. you class in part (i)), and returns a new instance of Complex. E-5 Improve the Complex class in DrScheme/ProfessorJ, so that it keeps track of how many instances of the Complex is created, and how many instances are alive. Use a static counter to count instances, and use the destructor to detect how many instances are alive.

5.2

Reection

Since a class is like any other object in Java it is possible to inspect its members, such as class methods. This is called reection in Java. Since it is an advanced topic we do not cover reection in this course. The curious readers are recomended to consult Reference documentation of the Class class, and consult relevant tutorial lessons at java.sun.com website. Classes and methods can be passed around and inspected as other Java entities. It is possible to inspect classes and objects using a group of reection

CHAPTER 5. CLASSES, TYPES, AND OBJECTS

31

tools in Sun JDK. Following is a demonstration of these mechanisms. Please refer to http://java.sun.com/developer/technicalArticles/ALT/Reection/index.html for an extensive review. class A{ A() {} String summary() { return String.format("This is an instance of %s", this.getClass().getName()); } } class B{ B() {} String summary() { return String.format("This is an instance of %s\n And it has a different this.getClass().getName()); } } class CFN { static void main(String[] args) { String input=System.console().readLine("Enter class name : "); try { Class c=Class.forName(input); I x=(I)(c.getConstructors()[0].newInstance()); System.out.println(x.summary()); } catch (Exception e) { System.out.println(e);} } }

Chapter 6 Using Industrial Grade Java Environments


Among descriptions of programming languages you will hear the terms compiled and interpreted. Compiled languages are those such as C and assembler, which take the program code you write and run it through a program called the compiler to produce the so called executable which can be directly understood (i.e. interpreted) by the computers CPU. On the other hand interpreted languages has no such intermediate conversion, but instead the program code is interpreted by the program called interpreter. Each system has its advantages. In compiled languages the end user will need the executable suitable for the hardware architecture(type of CPU and operating system) they have, in order to run your program. However with the advantage that the executable is optimized for the CPU. In the case of interpreted languages, on the other hand, end users need an interpreter for their architecture, but besides that can run the same program code on any architecture. Interpreted languages are somewhat more convenient, but compiled languages usually result in faster running programs1 . Java was designed to have best of both worlds. It is both a compiled and an interpreted language. To run a Java program one must rst run it through the Java compiler to produce the Java bytecode (the equivalent of executable). However, unlike C executable, Java bytecode is not intended to be interpreted directly by the CPU+operating system, but rather by an interpreter called the Java Virtual Machine (JVM). Although this may seem unnecessarily complicated, this design of Java resulted in excellent portability2 which Java owes its success. The JVM isolates Java software from the
For two reasons: (i)that since the code is already parsed, and (ii)compilers have the advantage of using CPU specic optimizations. 2 Portability is the ability of a computer program to work on dierent types of hardware
1

32

CHAPTER 6. USING INDUSTRIAL GRADE JAVA ENVIRONMENTS33 specics of hardware and operating system. Because of this isolation Java is extremely safe. For example a JVM that works inside your web browser provides the system for programs called Java applets. Since this JVM isolates the applet from the rest of your computer, they are safe to run and does not carry any risks. Also it has been possible to create JVMs -with reduced capabilities- for very small devices such as cell phones or credit card chips so that they can run Java programs. One of the most commonly used Java systems comes from Sun Microsystems, the designers of Java language. It is free to download Sun Java SDK(system development kit) which includes the compiler, the JVM, and many libraries you can use when writing programs. Many other systems are available such as commercial systems from Borland and IBM, or public licensed ones from GNU. If you are using a GNU/Linux system such as Ubuntu, you should be able to install Sun Java SDK on your system by running the following commands to install necessary packages: aptitude install sun-java6-jdk aptitude install sun-java6-jre aptitude install sun-java6-plugin First package installs Java compiler and libraries. The second installs the JVM. And the third enables your web browser to run Java applets. A simple type of Java program that we create using such systems is console based applications which does not have a graphical user interface. The industrial grade Java systems mentioned above use the same template to create such an application. Following is a piece of code that resembles Java Hello World applcation you will see in the rst pages of many Java books and online tutorials:

/** * A simple Java console based application * @author Mehmet Gencer */ public class HelloWorld { public static void main (String[] arguments) { System.out.println("Hello user!"); if (arguments.length>0) { System.out.println("You have run this program with the following argume for(int i=0; i< arguments.length; i=i+1) System.out.println(arguments[i]);
and operating systems.

CHAPTER 6. USING INDUSTRIAL GRADE JAVA ENVIRONMENTS34 } } } Save the code above in a le named HelloWorld.java. The le and the class must have the same name! Then compile as below:

javac HelloWorld.java If you see no error messages, you must have a new file named HelloWorld.class. Th java HelloWorld If you give command line arguments\mymark{command line arguments}, you will see t java HelloWorld a1 a2 a3 Hello user! You have run this program with the following arguments: a1 a2 a3 In summary, the requirements for having a console based Java application is therefore having a public class which has the same name with the le, and having a public and static method named main within that class. This is very much like setup() and draw() methods in Processing, the main() method is where Java will start executing your program. Please note that we have not created an instance of the HelloWorld class! Instead JVM invokes its static method to execute our application. The command line arguments we give to the program are passed by the JVM as an array of strings to the main() method. The statement which starts with System.out demonstrates an example of interacting with the user, which we will explore further in the following sections.

6.0.1

Why the static main() method?

When a Java program rst starts, all it knows are the classes imported from libraries (the next section) and classes dened by the user. There are no objects (except some everpresent obejcts, see the next section below). For this reason it is imperative that the entry method for the Java programs must be a static method! It is just a common convenience that all JVM implementations look for a class method (i.e. static method) named main as the starting point of the programs. This is much like the convenience of having setup() and draw() methods in PRocessing system.

CHAPTER 6. USING INDUSTRIAL GRADE JAVA ENVIRONMENTS35

6.1

Using Java libraries

Sun Java SDK comes in with a rich set of libraries you can use in your proograms. These range from mathematical facilities, to libraries for processing image or sound les. A reference documentation of all Sun JDK libraries (generated using javadoc) can be found at http://java.sun.com/javase/6/docs/api/. In order to use a library in your program, you must rst tell Java to import the library. To demonstrate these mechanisms we will now try to create a program which ask the user to enter numbers and nds their squareroot. For this application we will need the Math library to compute squareroots. Following is the program code: import java.lang.Math; public class RootFinder { public static void main(String[] arguments) { String input; do { input=System.console().readLine("Enter a number : "); if (input.length()>0) { double number=Double.parseDouble(input); double numberRoot=Math.sqrt(number); System.out.println(numberRoot); } } while (input.length()>0); System.out.println("Goodbye!"); } } The rst line imports the Math library. After that we can use the methods in the library with a syntax such as Math.sqrt(). You can imagine that this library is like the complex number class we have created, which is composed of static methods. For getting input from user we call System.console() which returns an object suitable for reading from the console by its readLine() method. But this method returns a string type value, so we must convert it to a real number using Double.parseDouble() method. Some classes we have used in the above program such as Double are builtin, we did not need to import anything to use them. However for the Math class we needed to import it. The import mechanism is necessary in Java to control capabilities of the system and bytecode size. For example in Java Mobile, which is a JVM that

CHAPTER 6. USING INDUSTRIAL GRADE JAVA ENVIRONMENTS36 works on cellular phones, or Java Micro, which works on much smaller devices such as credit card chips, some (most!) libraries wouldnt be available. java.sun.com provides the reference documentation for all essential objects in Java SDK, and for those that come in its standard libraries. When writing programs you will often need to consult the reference documentation. Make sure you use the appropriate version of the documentation. You can learn the version of the Java SDK you are using by invoking the javac command with -version option.

6.2

Everpresent objects in JVM

One special object, named System, exists when a Java program is started execution in tje JVM. The System object represents the operating system environment surrounding the JVM and allows one to access system properties or interact with the user using the system console in which the program runs. You are advised to read Java reference documentation of the System class to learn full features it provides.

6.3

Interacting with the user

One of the uses of System object is to print messages to the user console, or read input from it. The programs above have already demonstrated some uses such as System.out.println(...) statement. The in and out members of the System object are rather crude channels representing input from and output to user console. A more convenient way of interacting with user through the console is to obtain and use the Console object from the System, which has more convenient methods to do these things. The console can be used as in the following examples: import java.io.Console; ... String s=System.console().readLine("Enter some string please:"); ... String name="Mehmet"; int grade=50; System.console().format("Hello Mr. %s, your grade is %d", name, grade);

CHAPTER 6. USING INDUSTRIAL GRADE JAVA ENVIRONMENTS37

6.4

Exercises

E-1 Write a Java program which prints all System properties on the console output. E-2 Write a Java console application which takes an integer number as command line argument and reports its factorial. (Hint: use Integer.parseInt(some string) to convert a command line argument to an integer number.) E-3 Write a Java console application reads strings from the user and prints them in reversed form. (Hint: read the Java reference documentation of the String class) E-4 Write a Java program which computes Fibonacci number for large n, using BigInteger class from java.util library.

6.5

Handling errors in Java programs

Many unexpected errors may occur, especially when your program uses unchecked input from user of les. In many cases where an error (exception in Java parlance) is possible, Java compiler will warn you. But proper error handling, still relies on programmer skills. Following program demonstrates how exception handling mechanisms can be used in a program which expects a number from the user and reports its factorial. If the number cannot be properly converted to integer, program will report the error. public class Exceptions { static int factorial (int n) { if (n==1) return 1; else return n*factorial(n-1); } public static void main(String[] args) { String input=System.console().readLine("Enter a number : "); int n; try { n=Integer.parseInt(input); System.out.println(factorial(n)); } catch (NumberFormatException e) { System.out.println("You have mistyped the number.");

CHAPTER 6. USING INDUSTRIAL GRADE JAVA ENVIRONMENTS38 } } }

The new mechanism in the program is the try .. catch.. block. Which will try to execute the command block and if an exception occurs, it will take prescribed steps in the catch block corresponding to the exception type. There are several predened exceptions in Java, and NumberFormatException is one of them. For a list of Java predened exceptions, and a detailed review of exception mechanisms see http://java.sun.com/docs/books/tutorial/essential/exceptions/ Try running the above program, rst provide a valid positive integer, then type something dummy to see NumberFormatException. And nally give it a negative number, which will cause a runtime problem which cannot be captured by any catch block. To prevent this last problem, we have to redene our factorial method so that it will deny carrying out the calculation for an invalid value: public class Exceptions { static int factorial (int n) throws Exception { if (n<=0) throw new Exception("Negative value given!"); if (n==1) return 1; else return n*factorial(n-1); } public static void main(String[] args) { String input=System.console().readLine("Enter a number : "); int n; try { n=Integer.parseInt(input); System.out.println(factorial(n)); } catch (NumberFormatException e) { System.out.println("You have mistyped the number"); } catch (Exception e) { System.out.println("Unexpected error:"); System.out.println(e); e.printStackTrace(); } }

CHAPTER 6. USING INDUSTRIAL GRADE JAVA ENVIRONMENTS39 } In this version, the function denition declares that it potentially causes(throws) an exception of a certain type. The generic Exception type is the root of all exceptions. Also in this version we have used more than one catch block, which are chosen by Java according to the type of exception that occurs. The second catch block will catch any exception which is not catched by the previous one, and also uses the exception instance to print out detailed information about the error.

6.6

Self documenting programs

Java SDK comes with several useful tools. One of them, javadoc, is used for creating HTML documentation from your code comments. Try the following command: javadoc HelloWorld.java It will produce a le named index.html. Open the le in a web browser and see how it allows you to browse your classes and methods. For each class, method, or class variable, javadoc uses your comments which immediately precede the denition of class or method, or variable.

6.6.1

Exercises

E-5 Explore the javadoc manual page and nd out how to include author information in the generated documentation.

6.7

Proling Java processes

Even if one is very careful, certain programming mistakes can lead to programs which suer from bad performance. In such situations use of a proling tool can prove very useful. Recent versions of the Sun Java SDK comes with one such tool called jvisualvm. Using this tool, one can examine properties of live Java processes and JVMs, such as their memory usage, or where (which methods) the program spends its time. You are recommended to use this or similar tools to solve performance problems which you cannot gure out the reason by looking at your -potentially large- program code.

Chapter 7 Sub-classing and Inheritence


So far all the classes we have created stand on their own (except for mutual references). In many cases, however, we need mechanisms to avoid code repetition, and facilitate class access. A typical such case is when multiple sub-classes are needed to represent classes of objects that have many similar aspects, yet have their own peculiarities. Consider the case of dierent type of resources in the library. Dierent information needs to be kept for books and journals, yet some other information such as whether the resource is in the library or borrowed, its call number, etc., are common to two types. For such cases, Java (and other object oriented languages) oers the inheritence mechanism to solve the problem, so that all class members (variables and methods) can be inherited and extended by sub-classes. In the library example we rst dene the Resource class to represent aspects common to all resource types: |--------------------------------------| | Resource | |--------------------------------------| | String callID | | String title | | boolean isBorrowed | |--------------------------------------| | Resource(String callID, String title)| | String summary() | | void borrowed() | | void returned() | |--------------------------------------| We have included a summary() method in our class so that it can report the item to users, and two other methods to use when the resource is borrowed 40

CHAPTER 7. SUB-CLASSING AND INHERITENCE

41

and returned. Following is a Java console program which implements the class and creates a few instances to experiment with it:

class Resource { String callID; String title; boolean isBorrowed; Resource(String callID, String title) { this.callID=callID; this.title=title; isBorrowed=false; } String summary() { String summary; if (isBorrowed) summary=String.format("Call ID: %s \nTitle: %s\n not in library.",cal else summary=String.format("Call ID: %s \nTitle: %s\n in library.",callID, return summary; } void borrowed() { isBorrowed=true;} void returned() { isBorrowed=false;} } public class Library { public static void main(String[] arguments) { Resource[] resources=new Resource[3]; resources[0]=new Resource("QA76.1","Euclids geometry"); resources[1]=new Resource("QA73.2","Literate programming"); resources[2]=new Resource("QA73.3","Origin of the species"); resources[0].borrowed(); for (int i=0; i<resources.length; i=i+1) System.out.println(resources[i].summary()); } } When we want specic types of resources such as books and journals, a diculty arises. For books we need the author information in addition to variables of the Resource class. For the journals on the other hand we dont have author information, but instead we need the issue number. At this point we will use the sub-classing mechanism. The Book and Journal classes will be sub-classes of the Resource class. They inherit all variables and

CHAPTER 7. SUB-CLASSING AND INHERITENCE

42

methods, and extend it instead of re-implementing everything. Following is a Java console program using this method: class Resource { String callID; String title; boolean isBorrowed; Resource(String callID, String title) { this.callID=callID; this.title=title; isBorrowed=false; } String summary() { String summary; if (isBorrowed) summary=String.format("Call ID: %s \n else summary=String.format("Call ID: %s \n return summary; } void borrowed() { isBorrowed=true;} void returned() { isBorrowed=false;} }

Title: %s\n Title: %s\n

not in library.",

in library.",call

class Book extends Resource { String author; Book(String callID, String title, String author) { super(callID,title); this.author=author; } String summary() { return super.summary()+String.format("\n Author: %s",author); } } class Journal extends Resource { String issue; Journal(String callID, String title, String issue) { super(callID,title); this.issue=issue; }

CHAPTER 7. SUB-CLASSING AND INHERITENCE String summary() { return super.summary()+String.format("\n } }

43

Issue: %s",issue);

public class Library { public static void main(String[] arguments) { Resource[] resources=new Resource[3]; resources[0]=new Resource("QA76.1","Euclids geometry"); resources[1]=new Journal("QA73.2","ACM Transactions","March 2007"); resources[2]=new Book("QA73.3","Origin of the species","Charles Darwin"); resources[0].borrowed(); for (int i=0; i<resources.length; i=i+1) System.out.println(resources[i].summary()); } } Lets go over the new mechanisms in this program one by one: The Book and Journal classes are declared to extends the Resource class. They add new object variables such as author or issue. In the constructors of sub-classes, the constructor of the super-class (Resource) is invoked using super() Both classes override the summary() method, but when implementing it use the summary method of the superclass using super.summary(). In the main() method of the program, instances of Book and Journal classes are accepted as instances of Resource class. Book and Journal classes are considered as types that are compatible with the Resource type.

7.0.1

A note about the types

Note that the array in the example program above is an array of Resource type, although its contents are instances of dierent classes (Journal, Book, etc.). In Java (and most object oriented languages), an instance of a subclass passes as an instance of its super-class. THis is because the sub-class has everything the super-class has. We will see a similar type compatibility when we use interfaces in the following chapters.

CHAPTER 7. SUB-CLASSING AND INHERITENCE

44

7.1

Scopes, disambiguation, and overloading

As we have mentioned in Chapter 3 each variable or method dened has a scope within which it can be used. In Processing it was possible to use variables at the global scope (i.e. not inside any brackets). However when using industrial grade java environments, each variable or method must be inside a class, or its methods. When a variable is dened at the class level, it is accessible from every member method of the class. However you must remember that static members of a class are dierent fron those that are not. Since non-stati members belong to objects (class instances) and not to the class itself, you cannot, for example, use non-static variables or methods from within static methods. For example paarts of the the following code will cause an error: class C { int n=0; static int s=0; void getn() { return n; //OK } void gets() { return s; //OK } static void get2n() { return n; //ERROR!! } } Remember that although it is syntactically correct to access static variables from non-static methods, one must be very careful when doing so, because what is changed is the single copy of variable that is inside the class, not some variable that is peculiar to the instance. In certain situations a variable can become unreachable although it is in the scope. Consider the following example: class C { int n; C(int n) { n=n; // ??? WHICH n WE ARE TALKING ABOUT ? } }

CHAPTER 7. SUB-CLASSING AND INHERITENCE

45

Since the method parameter is in an inner scope, it shadows the variable in the higher scope. In the above situation, one can use the special variable, this, to refer to the class instance (ie. disambiguate the reference) as follows: class C { int n; C(int n) { this.n=n; // ??? WHICH n WE ARE TALKING ABOUT ? } } A similar problem is possible when a sub-class denes a variable or method which shadows the member of super-class in a similar manner. This is also the same problem when one needs to call the constructor of a superclass. One can use the special variable super to refer to the super-class in such situations. For example. class C { int n; ... } class C2 extends C { int n; //SHADOWS THE SUPER-CLASS VARIABLE void f() { n=super.n; } C2() { super(); //CALLS SUPER-CLASS CONSTRUCTOR ... } }

7.1.1

Overloading and overriding methods, method signatures

In the example above the meaning of having a constructor for a sub-class is actually overriding the construtor of the super-class. Because when the class is instantiated, the constuctor method invoked will be that of the sub-class, hence the constuctor of the super-class is overridden. Similar would be the case if a sub-class re-denes any of the super-class methods. In some cases it is necessary to allow dierent types of constuctors for a class. For example consider that we want to create a class to represent

CHAPTER 7. SUB-CLASSING AND INHERITENCE

46

a circle. We may want to allow the user to choose the coordinates and/or size of the circle, or if he/shee chooses they will be randomly assigned. The following class which denes multiple constructors does this: -----------------------------------------| | Circle | -----------------------------------------| | float r, x, y; | -----------------------------------------| | Circle(); | | Circle(float radius); | | Circle(float radius, float x, float y);| |---------------------------------------class Circle { float r, x, y; Circle() { r=random(100); x=random(300); y=random(400); } Circle(float radius) { r=radius; x=random(300); y=random(400); } ... } Although the three constructor methods all have the same name, Java will have no problem in choosing which one to invoke, because the given parameters to constuctor can help choosing which method to invoke. This is said as that the methods have dierent signatures (i.e. dierent parameter lists). This method of dening multiple methods with the same name but dierent parameter lists is called method overloading. It is particularly useful for class constructors, but nevertheless can be used for any class method.

7.2

Abstract classes and methods

A mechanism that can be used when implementing a group of related classes is the abstract classes and abstract methods. For example consider that we

CHAPTER 7. SUB-CLASSING AND INHERITENCE

47

want to implement uni-dimensional shapes such as circles, squares, and equilateral triangles. We know that all have a single dimension to be specied when constructed, but methods for drawing them or computing their circumferences are dierent. In such a case we can use a semi-implemented class which has some abstract methods as follows: abstract class Shape { float size; Shape(float size) { this.size=size;} abstract float circumference(); } Since some methods are abstract (and thus the class is incomplete), it is not allowed to create instances of this class. Instead we have to create classes which extend it and implement these methods: class Circle extends Shape { float circumference() { return PI*size*size;} } class Square extends Shape { float circumference() { return 4*size;} } Note that we had to implement only the abstract methods in our subclasses

7.2.1

Exercises

E-1 Consider that we want to implement dierent types of shapes in Processing. Use the abstract class mechanism to implement circles and squares in the program.

7.3

An example of extending JDK classes: Graphical user interfaces

Javas original popularity was largely due to graphical capabilities of Java Applets, which are Java programs that can run within a web page. Sun Java SDK not only have tools for creating applets but also provides libraries to create industrial grade graphical user interfaces. This section provides only a short peek into these capabilities. Please visit http://java.sun.com/applets/ for extensive tutorials.

CHAPTER 7. SUB-CLASSING AND INHERITENCE

48

An applet is designed to be displayed within an HTML page. Following is a simple applet and the HTML page to display it: import javax.swing.JApplet; import java.awt.*; import java.util.*; public class SimpleApplet extends JApplet { Date timestamp; public void init() { timestamp=new Date(); //current time } public void paint(Graphics g) { g.drawLine(0,0,this.getSize().width,this.getSize().height); g.drawString(timestamp.toString(), 5, 15); g.drawString(new Date().toString(), 5, 35); } } The class in the applet program extends the Applet class of JDK. The HTML page for displaying the applet is as follows: <html> <body> <p> My little applet:</p> <applet code="SimpleApplet" width=400 height=400> </body> </html> If you rst compile the Java program and then display the HTML page in a browser you will see the applet simply drawing a diagonal line. note that the HTML page and the Java class le must be in the same directory since the HTML applet tag indicates the code resides in the same directory. Applets have a limited use these days, but GUI applications are commonplace. Following is a standalone Java application which demonstrates how similar GUI libraries is used in standalone applications. It dows exactly what the applet above does, but this time in a window of its own: import javax.swing.*; import java.awt.*; class BasicApplication { static GUI gui; static JFrame mywindow; public static void main(String[] args) {

CHAPTER 7. SUB-CLASSING AND INHERITENCE gui=new GUI(); mywindow = new JFrame("My window"); mywindow.setSize(200, 300); mywindow.add(gui); mywindow.setVisible(true); } } class GUI extends JPanel { JButton button; GUI () { button=new JButton("Click here"); add(button); } public void paintComponent(Graphics g) { g.drawLine(0,0,100,100); } }

49

You can run the above application like any other JDk application, with the dierence that it will display a GUI window. The application uses library classes from Java Advanced Windowing Toolkit (AWT) and its newer, and richer cousing Swing. A Java GUI application has a JFrame as its window. A window frame may include a Panel (the main area), toolbars, and menus. Our little application uses only a panel, and places a clickable button on the panel. The panel itself is a drawable area much like the applet window. Our class, GUI, which extends the JPanel class has a method names paintComponent() which is called at the beginning to populate the content of the application window.

7.3.1

Exercises

E-2 Interesting fractal shapes can be produced using quadratic Julia sets on the complex numbers plane. A quadratic function is one which 2 is iterated as zn+1 = zn + c, where c is a complex constant. The Julia set corresponding to c is the set of points z0 which when the iteration does not approach innity. Write a JDK application which can read c from the user and draws the Julia set on the screen (e.g. by visualizing which points around the center of the complex plane belong to Julia set). Usually choosing a color based on how fast the function converges at a given point gives nicer looking results than

CHAPTER 7. SUB-CLASSING AND INHERITENCE monochromatic visualizations.

50

Chapter 8 Interfaces
A dierent type of problem arises when several classes are only similar in terms of behavior. For example consider shapes such as circles and rectangles in a drawing. All shapes will need to have methods to draw them, or compute their area. But other than this commonality, they share nothing. Drawing a circle or computing its area is not similar to doing the same for a rectangle. Therefore having a basic Shape class and extending it will not help us at all. On the other hand we certainly need to convenience of treating all shapes in the drawing similarly, as we have done in the main() method of our libaray application above. Books and Journals could both be treated as resources, and stored in the same array. In this chapter we will learn a mechanism which is a better alternative to abstract classes and methods we have learned before. A new mechanism, based on interfaces, is used for solving problems like the one in the shapes example. What we need to do is to design an interface which declares what methods an abiding class must have. Afterwards when we create dierent classes, we declare them as implementing the interface, so that they can be treated similarly (i.e. they are compatible types). We will implement this example in Processing. Following is our program: Shape[] shapes=new Shape[3]; void setup() { size(500,500); shapes[0]=new Circle(50,100,100); shapes[1]=new Rectangle(50,70,200,300); shapes[2]=new Rectangle(100,70,300,400); } void draw() { 51

CHAPTER 8. INTERFACES for (int i=0; i<shapes.length; i=i+1) shapes[i].draw(); } interface Shape{ void draw(); float area(); } class Circle implements Shape { float radius; float posX,posY; Circle(float radius, float posX, float posY) { this.radius=radius; this.posX=posX; this.posY=posY; } void draw() { ellipse(posX,posY,radius*2,radius*2); } float area() { return PI*radius*radius;} } class Rectangle implements Shape { float a,b; float posX,posY; Rectangle(float a, float b, float posX, float posY) { this.a=a; this.b=b; this.posX=posX; this.posY=posY; } void draw(){ rect(posX,posY,a,b); } float area() { return a*b;} }

52

Note that similar to the sub-classing method, classes that implement Shape interface are accepted as instances of Shape. Thus we are able to store shapes that are instances of dierent classes in an array of type Shape.

CHAPTER 8. INTERFACES

53

8.1

Multiple interfaces (or why interfaces are better than abstract classes)

A shortcoming -or rather a design preference- in Java is lack of polymorphism, i.e. a class can not be a sub-class of more than one class. However, intrfaces does not have this limitation. A class can extend only one claass but can implement as many interfaces as desired. For example consider in the shapes example above that there are shapes that can move. We can represent the behavioral blueprint of moving shapes in the following interface: interface MovingShape { void moveTo(float newX, float newY); } Now we can redefine our Circle class to implement both interfaces: class Circle implements Shape, MovingShape { ... void moveTo(float newX, float newY) { this.posX=newX; this.posY=newY; } } This new class can pass as an instance of both Shape and MovingShape.

8.2

Mixing the mechanisms

It is perfectly possible to use a mix of sub-classing, interfaces and abstract classes to implement a problem. Consider that we want to implement some uni-dimensional shapes which can also be moved in a coordinate system. Following is one possible solution to the problem: interface MovingShape { void moveTo(float newX, float newY); } abstract class UnidimensionalMovingShape implements MovingShape { float size, posX, posY; UnidimensionalMovingShape(float size, float posX, float posX) { this.size=size; this.posX=posX; this.posY=posY;

CHAPTER 8. INTERFACES } void moveTo(float newX, float newY) { this.posX=newX; this.posY=newY; } abstract float circumference(); } class Circle extends UnidimensionalMovingShape { float circumference() { return PI*size*size; } }

54

8.2.1

Exercises

E-1 Consider the dierent types of resources in a University library. Write an interface to represent the behavior of these resources. E-2 Consider a size limited buer to store integers. Write an interface to represent operations on such a buer. Make two implementations for rst-in-rst-out and last-in-last-out buers.

8.3

Example: Responsive GUI application

Note that the button in our previous GUI application application was not responsive, nor it was shut down when the window is closed. To add this capability we need to use several additional libraries. Following is an application which does a more complex work and also can sense button clicks and mouse location. The application will keep drawing a connnected series of lines as you click on its screen: import import import import import import javax.swing.*; java.awt.*; java.awt.geom.*; java.awt.event.*; java.util.*; javax.swing.event.*;

class BasicApplicationReactive { static GUI gui; static JFrame mywindow;

CHAPTER 8. INTERFACES public static void main(String[] args) { gui=new GUI(); mywindow = new JFrame("My Application"); mywindow.setSize(200, 300); mywindow.add(gui); mywindow.setVisible(true); mywindow.addWindowListener(new MyWindowAdapter()); } }

55

class GUI extends JPanel { JButton button; int x,y; LinkedList<Line2D.Double> lines; GUI () { x=0; y=0; lines=new LinkedList(); button=new JButton("Click here to reset"); button.setActionCommand("click"); button.addActionListener(new MyActionListener(this)); add(button); addMouseListener(new MyMouseListener(this)); } public void paintComponent(Graphics g) { g.clearRect(0,0,getSize().width,getSize().height); for (int i=0;i<lines.size();i+=1) ((Graphics2D)g).draw(lines.get(i)); } void moveTo(int newx, int newy) { lines.add(new Line2D.Double(this.x,this.y,newx,newy)); this.x=newx; this.y=newy; this.repaint(); } void reset(){ lines=new LinkedList(); getGraphics().clearRect(0,0,getSize().width,getSize().height); } }

CHAPTER 8. INTERFACES class MyWindowAdapter extends WindowAdapter { public void windowClosing(WindowEvent event) { System.exit(0); } } class MyActionListener implements ActionListener { GUI gui; MyActionListener(GUI gui) { this.gui=gui; } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("click")) gui.reset(); } } class MyMouseListener extends MouseInputAdapter { GUI gui; MyMouseListener(GUI gui) { this.gui=gui; } public void mouseClicked(MouseEvent e) { int newx=e.getX(); int newy=e.getY(); gui.moveTo(newx,newy); } }

56

The application introduces several additions to handle dierent kinds of events: Window events Events caused by user actions such as minimizing, maximizing, or closing the window (JFrame). Actions Events caused by clicking buttons, menu or toolbar items. Mouse events Any other mouse click inside the application window (panel). In this modied version, the GUI class implements ActionListener interface (from java.awt.event library) itself, so that it can respond to button click. On the other hand, seperate classes are used for the other two event types. The MyWindowAdapter is needed by the window (Frame) level only, thus it is added to the main window by addWindowListener() method of

CHAPTER 8. INTERFACES

57

JFrame. On the other hand mouse clicks in the drawing area are captured by MyMouseListener class, which is attached to the Panel as its mouse event listener, by addMouseListener() method of JPanel. The button click is identied by rst setting the action command at the beginning after JButton instance is created, then looking for the identication string as action events arrive. This version of the application maintains a list of lines (Line2d.Double class instances) and adds new lines extending to the point where user clicks the mouse. The button click will reset the lines list. Use of Line2d.Double class imposed the necessity to type cast Graphics to Graphics2D which can manage instances of this class. The mix of these classes is a result of historical development of JDK GUI libraries. At some point AWT development was ceased, and new classed were started to be developed as a part of Swing library. There are -seemingly- less painful ways of designing Java GUIs. The NetBeans IDE (Integrated Development Environment) from Sun Microsystems is one free software which can be used for designing GUIs by dragging and dropping visual elements to application window.

Chapter 9 Encapsulation and data safety in classes


You have probably noticed that the classes in the previous section contained variable and method modiers such as public. This access modier is one of several that allows us to control how a class member can be accessed. Lets rst see the motivations for access control in classes. Consider a class as follows to represent a circle: class Circle{ float radius; Circle(float radius) { this.radius=radius; } } Now we can create a circle and later set its radius: Circle c=new Circle(5); c.radius=-5; The assignment above is a mistake, but not a syntax error. The program will work and it is upon us to gure out something is wrong with the circle which has a negative radius! We must take control of how radius is set and does not allow invalid values. This requirement is an essential motivation for so called Model-View-Control (MVC) concept in many programming tasks. Java provides a mechanism to disallow access to class variables (and actually methods, as we will see later). The private and public modiers allow us to describe the level of access. By default everything is non-private, but it is a good exercise to make things explicit. The new class is as follows: 58

CHAPTER 9. ENCAPSULATION AND DATA SAFETY IN CLASSES59 class Circle{ private float radius; public Circle(float radius) { this.radius=radius; } public getRadius() { return radius; } public setRadius(float newRadius) { if (newRadius>0) radius=newRadius; } } With the denition above, any attempt to access radius of a circle directly is prohibited. The following line will produce an error: c.radius=5; //ERROR at compilation Following is a summary of the consequences of using access modiers on accessibility of elements: Modier Class Package Subclass World public Y Y Y Y protected Y Y Y N no modier Y Y N N private Y N N N NOTE: Where making encapsulation explicit whereever possible is the recommended practice, we omit doing so in most examples below to make them easier to read.

9.0.1

Exercises

E-1 Write a class to represent a bank account. The account should have variables to store account holders name, access password, and amount of money in the account, and have methods to withdraw money if the correct password is given.

9.1

Nested and anonymous classes

Not all classes need to be at the global scope, it is possible to dene a class within anothre class, for example to avoid its use beyond that: class Outer { ...

CHAPTER 9. ENCAPSULATION AND DATA SAFETY IN CLASSES60 private class Inner { ... } Inner i; In a dierent way, one may wish to use a class which is not used anywhere except one point in the program. In such cases it is possible to dene an anoynymous class as follows: class C { void someMethod(java.util.Enumeration) { ... } ... someMethod(new java.util.Enumeration() { public boolean hasMoreElements() { ... } public Object nextElement() { ... } }); Note that an anonymous class has not name and it can only be dened as extending a class or implementing an interface.

Chapter 10 Implementing data structures


10.1 Self-references, mutual-references

We have seen that classes have variables to keep data about objects. There is no limitation that prevents us having a variable whose type is a class we create, or even the class it is dened within. For example consider the problem of representing the sales in a shop. There will be many sales during the day and we dont know how many. Thus using a xed size array is not a suitable solution. A way of overcoming the problem is to store a chain of sales (a linked list), in which each sale points to the next, and the last one points to nothing: class Sale{ float amount; Sale next; Sale(float amount) { this.amount=amount; next=null; } } What we have done is called self-referencing since on of class variables is of the type class itself. We left the variable having a value of null since we do not know its value before another sale is created. However we can have a second constructor for cases we want to support values for both variables: class Sale{ float amount; Sale next; Sale(float amount) { 61

CHAPTER 10. IMPLEMENTING DATA STRUCTURES this.amount=amount; next=null; } Sale(float amount, Sale next) { this.amount=amount; this.next=next; } }

62

What we have done is called method overloading, as we have multiple definitions for the same method. Since two denitions have dierent argument lists, Java can choose one depending on how we instantiate the class. Following is an example piece of code to enter a few sale operations into a system using the class above: Sale lastSale=null; lastSale=new Sale(100); lastSale=new Sale(200,lastSale); In other situations we may have more than one class in our programs which are somehow related. For example consider that we want to store who sold what when we keep sale records in the above example. It is apparent that we will have a class to represent salesman. Lets rst draw the class diagram for this system: |-----------------------------| |---------------------------| | Sale | |Salesman | |-----------------------------| |---------------------------| |float amount |<--|Sale saleChain | |Sale next | |String name | |Salesman sm |-->|---------------------------| |-----------------------------| |Salesman(String name) | |Sale(float amount) | |void addSale(float amount) | |Sale(float amount,Salesman sm) |---------------------------| |Sale(float amount,Salesman sm, | Sale next) | |-----------------------------| Note how we used arrows to indicate mutual referencing between the two classes. The class diagrams present a complete view which allows manipulating the system. Now we can proceed to write the two classes. class Sale{

CHAPTER 10. IMPLEMENTING DATA STRUCTURES float amount; Sale next; Salesman sm; Sale(float amount) { this.amount=amount; next=null; sm=null; } Sale(float amount, Salesman sm) { this.amount=amount; this.sm=sm; next=null; } Sale(float amount, Sale next, Salesman sm) { this.amount=amount; this.sm=sm; this.next=next; } } class Salesman { Sale saleChain; String name; Salesman(String name) { this.name=name; } void addSale(float amount){ saleChain=new Sale(amount,saleChain,this); } } Now we can enter sales for dierent salesperson: Salesman sp1=new Salesman("ali"); Salesman sp2=new Salesman("ayse"); sp1.addSale(100); sp2.addSale(200); (See ? for a more detailed discussion on self and mutual references)

63

10.1.1

Exercises

E-1 Add a method to Salesman class which nds total amount of sales by the salesperson.

CHAPTER 10. IMPLEMENTING DATA STRUCTURES

64

E-2 We want to represent books in the library and their authors using Java classes. For books we want to store book title and author of the book. For authors we want to store their name. Create class diagrams for both classes. E-3 Implement a stack of integers which provide methods for pushing and popping values from the stack, and returning the size of stack. If the stack is empty, simply return 0 when one attempts to pop a value.

10.2

Variable size data: implementing mutable lists

When the amount of entities to be stored are not known in advance, immutable lists (Java arrays) are not much useful. A common remedy is using a linked list, in which each item knows the reference of the next item, thus forming a chain. Such a self-referential class for storing integers would be as follows: class IntegerList { int n; IntegerList next; ... } Obviously one would need methods to add, remove, or access elements of the list. Linked lists vary according to how elements are added and removed (e.g. stacks, queues, sorted lists, etc.). Following program demonstrates how a stack can be implemented: class ListItem { int n; ListItem next; ListItem(int n) { this.n=n; next=null; } ListItem(int n, ListItem next) { this.n=n; this.next=next; } }

CHAPTER 10. IMPLEMENTING DATA STRUCTURES class IntegerStack { ListItem header; IntegerStack() { header=null; } void push(int n) { header=new ListItem(n, header); } int pop() { ListItem retval=header; header=header.next; return retval.n; } boolean isEmpty() { if (header==null) return true; else return false; } } public class Stack { public static void main (String[] args) { IntegerStack stack=new IntegerStack(); stack.push(1); stack.push(2); while (!stack.isEmpty()) System.out.println(stack.pop()); } }

65

Linked lists are very commonly used and Java SDK provides libraries to avoid implementing the above functionality each time a mutable list is needed. Following program has the same functionality with the above one using LinkedList class from java.util library: import java.util.*; public class JavaList { public static void main(String[] args) { LinkedList stack=new LinkedList(); stack.push(1); stack.push(2);

CHAPTER 10. IMPLEMENTING DATA STRUCTURES while (!stack.isEmpty()) System.out.println(stack.pop()); } }

66

The LinkedList implementation aditionally oers exporting the data as an array, which comes handy in some cases. Since the LinkedList stored the generic Object type, its use may involve typecasting in most cases beyond our simple integer list. To avoid this LinkedList variables can be declared to hold a specic type as in the following example: LinkedListString list; Example: Books and authors Consider an application to store information about books in a library and their authors. Each book will have more than author, and each author is releated to several books. Also the amount of books in the library is subject to change. Following is a solution to the problem: import java.util.*; class Author { String name; LinkedList<Book> books; Author(String name) { this.name=name; books=new LinkedList(); } void addBook(Book book) { books.add(book); } void printSummary() { System.out.println(name); for (int i=0; i<books.size();i=i+1) System.out.println(String.format(" } } class Book { String title; LinkedList<Author> authors; Book(String title) { this.title=title; authors=new LinkedList();

%s",books.get(i).title));

CHAPTER 10. IMPLEMENTING DATA STRUCTURES

67

} void addAuthor(Author author) { authors.add(author); } void printSummary() { System.out.println(title); for (int i=0; i<authors.size();i=i+1) System.out.println( String.format(" author: %s",authors.get(i).name)); }

} public class Library { /** * Find author in the authors list and return. Return null if * author is not in the list. */ static Author findAuthor(LinkedList<Author> authors, String name) { for (int i=0; i<authors.size(); i=i+1) //Note that string comparison is different from primitive types if (authors.get(i).name.equals(name)) return authors.get(i); return null; } public static void main(String[] args) { LinkedList<Author> authors=new LinkedList(); LinkedList<Book> books=new LinkedList(); String title; do { //loop to enter books title=System.console().readLine( "Enter the book title (or empty to finish) : "); if (!title.equals("")) { Book book=new Book(title); String authorName; do { // loop to enter authors of a book authorName=System.console().readLine( "Enter the author name (or empty to finish) : "); if (!authorName.equals("")) { //first check if author already exists Author author=findAuthor(authors, authorName); if (author==null){ //author does not exist, create i author=new Author(authorName);

CHAPTER 10. IMPLEMENTING DATA STRUCTURES authors.add(author); } book.addAuthor(author); author.addBook(book); } }while(!authorName.equals("")); books.add(book); } } while (!title.equals("")); System.out.println("BOOKS IN THE LIBRARY"); for(int i=0; i<books.size();i=i+1) books.get(i).printSummary(); System.out.println("AUTHORS IN THE LIBRARY"); for(int i=0; i<authors.size();i=i+1) authors.get(i).printSummary(); } }

68

Chapter 11 Object serialization and persistence


An object that resides in the memory of JVM can be serialized, i.e. turned into a sequence of bytes from which the object can be recovered in its state at the time of serialization. The possibility of serializing objects have many advantages such as the ability to store them in a le to be later recovered, or transferring them over the Internet to another JVM in another computer (e.g. in e-business). The only requirement for a Java class to be serializable is to implement the interface called Serializable, which requires no methods to be implemented. Any object which is an instance of a class implementing Serializable interface can be given to an ObjectOutputStream instance (from java.io library) to be written out. The following example demonstrates how the serialization can be invoked on a LinkedList which already implements Serializable interface: import java.io.*; import java.util.*; class Serialize { public static void main(String[] args) { LinkedList list=new LinkedList(); list.add(1); list.add(2); try { ObjectOutputStream so = new ObjectOutputStream(System.out); so.writeObject(list); } catch (IOException e) { System.out.println("Problem writing object"); System.out.println(e); 69

CHAPTER 11. OBJECT SERIALIZATION AND PERSISTENCE } } }

70

The serialized form printed on the screen by the above program is not readable. However it is only intented to be read by Java de-serialization. The following demonstrates how to persist serialized objects which are instances of our classes into a le. When the program is rst run, it will store an object in the le myobj, and in later runs of the program it will recover the object instead of creating a new one. Try running the program more than once. import java.io.*; class TimeChecker implements Serializable{ long time; TimeChecker () { this.time=System.currentTimeMillis(); } long getTime() { return this.time; } } class PersistenceExample { public static void main(String[] args) { TimeChecker tc; //de-serialize object if the file exists, create new one otherwise try { FileInputStream file = new FileInputStream("myobj"); ObjectInputStream si = new ObjectInputStream(file); tc = (TimeChecker) si.readObject(); file.close(); } catch(Exception e) { System.out.println("No file is found. I will use a new object"); tc = new TimeChecker(); } System.console().format("Object time is %d%n",tc.getTime()); try { FileOutputStream fileout = new FileOutputStream("myobj");

CHAPTER 11. OBJECT SERIALIZATION AND PERSISTENCE

71

ObjectOutputStream so = new ObjectOutputStream(fileout); so.writeObject(tc); so.close(); } catch(Exception e) { System.out.println("Cannot write out"); } } } We must note that the Java program which de-serializes the object must have the class denition of the object which is being deserialized, otherwise the class of the object cannot be identied. This is not a problem when the object is an instance of a standard Java class such as the LinkedList, but it matters for our own classes.

11.0.1

Exercises

E-1 Improve the library example above so that the books and authors lists will be persisted before program exits.

11.1

Using Databases

Many database engines provide Java libraries. Here we cover the SQLite embedded database as an example since it requires little conguration overhead. However for large scale, high performance applications more capable database engines, such as PostGreSQL or Oracle, are recommended. Information on SQLite can be found at http://www.sqlite.org/. The Java library used for this tutorial comes from http://www.zentus.com/sqlitejdbc/. Download the .jar le containing the library and keep it where either (i) your want to keep your source les, or (ii) inside the lib subdirectory of your Java JDK. From an application programmers perspective all relational databases are somewhat similar since -almost- all use the Standard Query Language (SQL) for access and manipulation. When using a database one may create/destroy tables, add/delete/update or select records from these tables. It is possible to do all these operations using either (i) user interface programs that comes with the database which access the database directly (or indirectly or remotely, depending on the multi-tier structure and complexity of the database engine), or (ii) by writing programs which access the database using available libraries.

CHAPTER 11. OBJECT SERIALIZATION AND PERSISTENCE

72

In the case of most high-performance, industrial grade database engines, access to database is controlled by a running process called the database engine. The engine makes sure that all access to database is properly authorized (usually using a ne grained access control mechanism) and also that no accidents happen when there are multiple concurrent accesses. However SQLite is simply an embedded database, and it does not have such an engine that is always up and running and keeping the gates. Instead an SQLite database is simply a le and any process who have access to this le have full access to the database. When one application is using the database it is locked and cannot be modied by another application. Therefore, as an embedded database, SQLite lacks many features in both fronts. But it is nevertheless practical and have a good performance, making it a simple and eective solution for some type of applications. Despite these dierences writing database programs are similar and Java SDK provides certain common aspects of database access already, except the implementations themselves. As other database systems, SQLite also uses the standard Java DataBase Connectivity layer (JDBC) and java standard edition SDKs java.sql library. Following program demonstrates SQLite usage from Java:

/** * SQLite Java library usage example. Adopted from http://www.zentus.com/sqlitejd */ import java.sql.*; import org.sqlite.JDBC; class SQLiteExample { public static void main(String[] args) throws Exception { new JDBC(); //initialize the SQLite JDBC system so that the database // descriptor in the next line is usable Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db"); Statement stat = conn.createStatement(); stat.executeUpdate("drop table if exists people;"); stat.executeUpdate("create table people (name, occupation);"); PreparedStatement prep = conn.prepareStatement( "insert into people values (?, ?);"); prep.setString(1, "Gandhi"); prep.setString(2, "politics"); prep.addBatch(); prep.setString(1, "Turing"); prep.setString(2, "computers"); prep.addBatch();

CHAPTER 11. OBJECT SERIALIZATION AND PERSISTENCE prep.setString(1, "Wittgenstein"); prep.setString(2, "smartypants"); prep.addBatch(); conn.setAutoCommit(false); prep.executeBatch(); conn.setAutoCommit(true);

73

ResultSet rs = stat.executeQuery("select * from people;"); while (rs.next()) { System.out.println("name = " + rs.getString("name")); System.out.println("job = " + rs.getString("occupation")); } rs.close(); conn.close(); } } To compile the above program you need to specify where the SQLite Java library is located. For example if the library (.jar le) is in the same directory with the program, compile it as follows: javac -cp sqlitejdbc-v054.jar SQLiteExample.java Similarly you will need to specify classpath when executing the program: java -cp .:sqlitejdbc-v054.jar SQLiteExample If you read the program you will see that four classes are used for database access: Connection, Statement, PreparedStatement, and ResultSet. Connection represents a connection to the database. Location and type of database is indicated when a connection is opened. Statement and PreparedStatement classes are used to execute SQL statements. The latter is used in cases where a statement will be executed multiple times with dierent parameters. The ResultSet represents a list of records selected with a statement. When using SQLite databases you must make sure that you close the connections as soon, otherwise it will be blocked for write access by other processes that use the same database. Normally SQLite driver is set for auto commit, so that statements will be executed when they are issued. However in many cases it is faster and practical to execute a batch of related statements at once, so that they will either succeed or fail alltogether. Such transaction management is an essential practice in database programming to reduce errors, in addition to increasing performance in many cases.

CHAPTER 11. OBJECT SERIALIZATION AND PERSISTENCE

74

11.1.1

Exercises

E-2 Redo the library example in Exercise E-1 using an SQLite database for persisting library data.

Chapter 12 Java packages


So far we have put all classes needed for our applications in a single source le. This method does not scale well when applications get more complex. Java packages provide the mechanism for organizing code. Packages also provide an additional layer of isolation using the protected members as we will see. We have been already using Java packages, whenever we have used the import statement in out programs. When we want to create a package like those, we need to do two things: 1. Put a package declaration at the top of the source le such as package xxx. There is a certain package naming convention in the Java programming community. Packages that start with java.xxx comes from Sun Microsystems. Those taht start with org and com come from non-prot and for-prot organizations, respectively, usually denoting the organization or project name, such as org.apache.xml, etc. 2. Place the source les for the same package under a directory structure that resembles its name. For example les for a package named org.bilgi.complex must go under directory org and in that a subdirectory named bilgi etc. We have previously used only public or private modiers for classes and their members, or used none. With the additional level of organization using Java packages we can cover one more modier: the protected modier. Table 12.1 summarized where can a class or its members be accessed from when each modier is used or no modier (so called package-private) is used: In addition to these, the nal modier prevents a class from being extended or a method from being overridden. The major type of situation where this might be useful is when part(s) of software is in an experimental state and 75

CHAPTER 12. JAVA PACKAGES Table Class Y Y Y Y 12.1: Access allowed Package Subclass Y Y Y Y Y N N N by Java modiers World Y N N N

76

Modier public protected no modier private

sub-classing can cause a series of troubles. In such cases the nal modier can be used to prevent sub-classing until the package reaches some level of maturation. As an example package we will put a complex number implementation and Julia set visualization GUI code (see below) into a package named org.bilgi. In order to do that we will create a directory named org and a subdirectory under it named bilgi. Inside that directory create a le, preferably named Complex.java for convenience (but it does not really matter as far as its extension is .java!). That le will contain the complex number implementation as follows: package org.bilgi; /** * A Complex number implementation for use in quadratic Julia set * computations */ class Complex { double r,i; Complex(double r, double i) { this.r=r; this.i=i; } double getReal() {return r;} double getImag() {return i;} Complex square() { double newr=r*r-i*i; double newi=r*i*2; return new Complex(newr,newi); } Complex add(Complex with) { return new Complex(r+with.getReal(),i+with.getImag()); }

CHAPTER 12. JAVA PACKAGES double length() { return Math.sqrt(r*r+i*i); } /** * Return how fast the quadratic function converges */ int julia(Complex c, int numIterations, double cutoff) { Complex next=new Complex(r,i); for(int i=0; i<=numIterations; i++) { next=next.square().add(c); if (next.length()>=cutoff) return i; } return numIterations; } /** * Return the quadratic function value for coloring */ Complex juliaValue(Complex c, int numIterations) { Complex next=new Complex(r,i); for(int i=0; i<=numIterations; i++) { next=next.square().add(c); } return next; } }

77

The source code starts with a declaration package org.bilgi; to indicate that it is part of a package with given name. Also some of the methods are declared as protected since they are only experimental and I do not want to make them available outside the package. In a separate source le in the same directory I will place the Julia set visualization GUI, which makes use of the Complex class above. The le is almost the same with the le given at the end of the tutorial as an answer to the exercise, except that (i) Complex class is removed and placed in another le as we have seen above, and (ii) the code starts with a package declaration and and the application class is declared public so that it can be used when the package is imported elsewhere. I have chosen the name JuliaSetFractals.java for my le which goes as follows: /**

CHAPTER 12. JAVA PACKAGES

78

* Implementation of quadratic Julia sets. * Author: Mehmet Gencer, mgencer@cs.bilgi.edu.tr, 2008 * * Try to redraw the Julia fractal using values: * (-0.4,0.6), (0.285,0.01), (-0.835,-0.2321) * clicking on a point on the display area will recenter the drawing */ package org.bilgi; import import import import import import javax.swing.*; java.awt.*; java.awt.geom.*; java.awt.event.*; java.util.*; javax.swing.event.*;

class JuliaSetFractals { static FractalGUI gui; static JFrame mywindow; public static void main(String[] args) { gui=new FractalGUI(); mywindow = new JFrame("Julia Set Fractal Renderer"); mywindow.setSize(400, 400); mywindow.add(gui); mywindow.setVisible(true); mywindow.addWindowListener(new MyWindowAdapter()); } } class FractalGUI extends JPanel{ JButton button; JTextField r,i; int centerX,centerY; double scale=150; //scaling Complex c; FractalGUI () { button=new JButton("Click here to draw fractal"); button.setActionCommand("click"); button.addActionListener(new MyActionListener(this));

CHAPTER 12. JAVA PACKAGES r=new JTextField("-0.4",10); i=new JTextField("0.6",10); add(r); add(i); add(button); addMouseListener(new MyMouseListener(this)); centerX=200; centerY=200; c=new Complex(-0.4,0.6);

79

} public void paintComponent(Graphics g) { g.clearRect(0,0,getSize().width,getSize().height); int numiter=20; double cutoff=scale; for (int x=0;x<getSize().width;x=x+1) for (int y=0;y<getSize().height;y=y+1) { double real=(x-centerX)/scale; double imag=(y-centerY)/scale; Complex p=new Complex(real,imag); int pj=p.julia(c,numiter,cutoff); Color color; if (pj>=numiter) { Complex pjv=p.juliaValue(c,numiter); color=Color.getHSBColor((float)(pjv.length()/scale),(float)pj } else color = new Color((float)pj/numiter,(float)pj/numiter,(float) g.setColor(color); g.fillRect(x, y, 1,1); } //draw the axes g.setXORMode(Color.white); g.drawLine(centerX,0,centerX,getSize().height); g.drawLine(0,centerY,getSize().width,centerY); g.setPaintMode(); } void recenter(int newx, int newy) { System.out.println("Recentering"); centerX=newx; centerY=newy; repaint();

CHAPTER 12. JAVA PACKAGES } void redraw() { try { double newr=Double.parseDouble(r.getText()); double newc=Double.parseDouble(i.getText()); c=new Complex(newr,newc); } catch(NumberFormatException e) { System.out.println("Invalid value given!"); } repaint(); } void revalue(int newx, int newy) { double real=(newx-centerX)/scale; double imag=(newy-centerY)/scale; c=new Complex(real,imag); r.setText(String.format("%f",real)); i.setText(String.format("%f",imag)); repaint(); } } class MyWindowAdapter extends WindowAdapter { public void windowClosing(WindowEvent event) { System.exit(0); } } class MyActionListener implements ActionListener { FractalGUI gui; MyActionListener(FractalGUI gui) { this.gui=gui; } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("click")) gui.redraw(); } } class MyMouseListener extends MouseInputAdapter { FractalGUI gui; MyMouseListener(FractalGUI gui) {

80

CHAPTER 12. JAVA PACKAGES this.gui=gui;

81

} public void mouseClicked(MouseEvent e) { int newx=e.getX(); int newy=e.getY(); if (e.getButton()==MouseEvent.BUTTON3) //if right-click, choose c from gui.revalue(newx,newy); else gui.recenter(newx,newy); //if left-click, recenter drawing } } Note that we do not need to import the Complex class although it is in a separate le. This is because the two source les are part of the same package. The trick, however, lies in the fact that the two les must be compiled at once, as follows: javac Complex.java JuliaSetFractals.java Any attempts to compile the rst, then the second will fail! As I have a new package, I can now write applications which use the package: import org.bilgi.*; public class PackageUser { public static void main(String[] args) { JuliaSetFractals jsf=new JuliaSetFractals(); jsf.main(args); } } When compiling the message make sure that either the org directory where our package resides is in the same directory with the program, or you modify the Java classpath (using -cp option of javac command) when compiling and running the program.

12.0.2

Distributing multi-le Java applications: jar archives

When your application consists of one or more packages and some other les that use those packages, it becomes hard to distribute them. You will need to provide detailed instructions for users to create the proper directory

CHAPTER 12. JAVA PACKAGES

82

structure, which creates quite an error prone situation. A solution for these type od situations is to use Java archives, or simply jars. Sun JDK comes with a program named jar to create or extract such archives. For example you can create an archive containing our package and the application that uses the package as follows: jar cvf bundle.jar org PackageUser.java However jar is more powerful than, for example, zip archives. It is possible to use jar les as executables. In order to do that we must tell Java which class is the one to be loaded as an application. The way to do this is to create a le named manifest.mft which contains the following: Manifest-Version: 1.0 Main-Class: PackageUser Class-path: . then use the jar command as follows: jar cvfm bundle.jar manifest.mft org PackageUser.java Now you can execute the created archive as follows: java -jar bundle.jar This makes distribution of multi-le Java software more practical.

Appendix A A guide for coding style


Computer programs are not merely for compilers and interpreters. On the contrary, a more frequent type of access happens when we open the program for improving, or nding bugs, or when a team-mate does the same. Therefore, a program needs to be understandable when we need to recollect what we have done previously, or when it is the object of collective work. In this regard, programming is an art form, not only because it is an applied craft of mathematical abstraction, but also as the presentation of this abstraction in the form of a program is a piece of writing which should demonstrate a pleasant and readable style. A rst condition for coding style is consistency in using symbols and delimiting parts of program. When one writes literature, one follows certain established rules in using punctuation marks (i.e. periods at the end of sentence), capital letters (i.e. rst letter of sentence, or private names start with capital letters), or demarcating text (i.e. starting new paragraphs or pages). Similar rules emerged through the programming practice in half a century of its existence. These rules are not universal, just as dierent national languages vary in their rules of writing them. Dierent programming languages, or some programmer communities can dier in the style rules they follow. In this guide we try to present most common rules used in the world of programming.

A.1

Demarcation

One of these established rules regards demarcation of dierent scopes in a program. This is established by using consistent indentation for program statements that are at the same level, and increasing indentation level as scopes are nested within one another. Following piece of Java code demon83

APPENDIX A. A GUIDE FOR CODING STYLE strates how this is applied: int factorial (int n) { if (n<=1) return 1; else return n * (n-1); }

84

In the above program the function scope is indented with four spaces. The nested scope of if statement is indented further: int factorial (int n) { --->if (n<=1) ------->return 1; --->else ------->return n * (n-1); } The program also demarcates parts of statements with spaces. For example if is written as below: int factorial(int n){ if (n<=1) return 1; else return n*(n-1);} it becomes considerably less appealing to its reader and very hard to understand. There are minor variations in how this rule is applied. For example some prefer to place brackets encapsulating scopes as follows: int factorial (int n) { if (n<=1) return 1; else return n * (n-1); } Although this variant of the rule seems more logical, we will follow the rst version of the rule, merely due to the fact that it is more common in the programming community.

APPENDIX A. A GUIDE FOR CODING STYLE

85

A.2

Organization

Generally the data has precedence over the process. This is reected in our second rule of placing variable declaration statements before other statements in the programs. For example in dening a Java class as follows: class Complex { double real; double imaginary; Complex (double real, double imaginary) { this.real = real; this.imaginary = imaginary; } double getMagnitude () { return Math.sqrt(real*real + imaginary*imaginary); } ... Dierent programming languages may follow further renements in code organization. For example in Java programming, it is a common practice to place static members before non-static members, and constructor methods before any other method. Therefore on top of variables preceding methods, static variables must precede non-static ones, and static methods precede non-static ones but come after constructors. For example: class Circle { static double PI = 3.14; double radius; Circle (double radius) { this.radius = radius; } static double area (Circle c) { return PI * c.radius * c.radius; } double area () { return area(this); } ...

APPENDIX A. A GUIDE FOR CODING STYLE

86

A.3

Explanation

Each programmer have a dierent and unique approach, and even ones approach will be dierent in two years time. Although how you do things may in many cases seem trivial to you, it is a good practice to explain key elements of your program in plain natural language. For this reason all programming languages provide a means of placing comments, lines or blocks of text which is marked to be excluded from program compilation or interpretation, but rather put for the human readers. Today it became a common practice to place short or long comments at top of program les, near classes, functions, or variables, and even within intermediate points inside functions to explain what is going on. The following example uses such comments extensively (some lines are split to t on the page): /** A program to draw Julia set fractals. * Author: Mehmet Gencer, mgencer@cs.bilgi.edu.tr * Created: 24 Nov 2008 * * This program is free software and provided without any guarantees. * You can redistribute this program in original or modified form * provided that this copyright notice is preserved. */ /** * Complex class represents a complex number, and provides additional * methods for convergence checking in quadratic Julia sets. */ class Complex { double real; // real part of the complex number double imaginary; // imaginary part of the complex number ... /** * Return square of the complex number */ Complex square () { double newr = real*real - imaginary*imaginary; double newi = real*imaginary*2; return new Complex(newr,newi); }

APPENDIX A. A GUIDE FOR CODING STYLE

87

/** * Check whether a quadratic function in the form z_(i+1)=z_i^2+c * diverges for given z when iterated. If the magnitude of z * exceeds threshold after at most maxIterations number of iterations * it returns true, otherwise it returns false. */ static boolean checkDivergence (Complex z, Complex c, double treshold, int maxIterations) { Complex znext; //variable to store next value in iteration //iterate up to maxIterations, // but if threshold is exceeded in the meantime, return true immediately znext=z; for (int i=0; i < maxIterations; i = i+1) { znext=znext.square().add(c); if (znext.getMagnitude() > treshold) return true; } return false; } ... In the above example the comments at the top of the program briefs what program does, who wrote it and when, and what one can do with it. Each class and method is preceded with a long comment. All variables are succeeded with short comments. And the relatively longer method, checkDivergence(), has comments within the method body. The above example demonstrates a very common way of code documentation, used in java and C/C++. Indeed there are various programs written to produce software reference documentation automatically from such code comments. However this rule also has variations. For example Python programmers place code comments after method or class denitions, an Python environment has documentation tools based on this.

A.4

Explication

Excessive use of comments may become a handicap to readability of the program. One remedy for this problem is to choose explicit, self-explanatory names for your methods or variables which eliminates further explanation in code comments. For example if the factorial function was declared as follows, it would denitely require code comments:

APPENDIX A. A GUIDE FOR CODING STYLE int f (int i) { ... }

88

as the function name is nowhere near being self-explanatory. Long names may feel cumbersome at the beginning, but youll come to appreciate their virtue as you re-visit your programs.

A.5

Naming conventions

There are various names in a program: for classes, for variables, for methods, etc. Also in related to explication, you may have to have variable or method names that are longer than a single word. There are competing trends in how one should choose names. Here we describe the most common methods in the Java programming world: Class or Interface names start with a capital letter, and interfaces are commonly prexed with an I. For example: Complex, IIteratorInterface, LogicException, etc. Variable or method names start with a small case, but if it consists of multiple words rst letter of each word is capitalized for ease of reading. For example: i, x, real, nextValue, getSize(), etc. Constants are in capital letters, and if they consist of multiple words the words are separated by underscores. For example: PI, MAX LENGTH, etc.

Bibliography
Brooks, F. P. (1995). The mythical man-month : essays on software engineering. Addison-Wesley. Felleisen (2004). How to Design Classes. Zakhour, S., S. Hommel, J. Royal, I. Rabinovitch, T. Risser, and M. Hoeber. The Java Tutorial: A Short Course on the Basics, 4th Edition. java.sun.com/docs/books/tutorial/java/nutsandbolts/index.html.

89

Index
arrays, 13 compiled languages, 32 compiler, 32 constructor, 21, 25, 30, 45, 46, 61, 85 contracts, 24 declarative, 2, 7 executable, 32 for loops, 14 functional, ii, 1, 24 imperative, ii, 2, 6, 7, 34 inheritence, 40, 41 interpreted languages, 32 interpreter, 32 iteration, 2, 7, 11, 14 Java Virtual Machine (JVM), 32 libraries, 33 method overloading, 62 mutual references, 62 overriding, 45 overriding methods, 43 SDK, 33 static, 29, 30, 34, 35, 44, 85 strictly typed, ii, 2, 3, 6, 13, 28 Sun Java SDK, 33

90

INDEX [default]

91

Potrebbero piacerti anche