User:Lstor
From Wikipedia, the free encyclopedia
[edit] From Python to Java
[edit] Why learn Java?
- Java is faster.
- Java is more suitable for larger systems, because it is a stricter language.
- Which also makes it easier to debug.
[edit] Our first example: Hello, World!
Let's get right to the code. We'll start with a program that most languages are introduced with: The Hello World program.
|
|
[edit] Code analysis
On line 1, we start the class definition of our entry point class, designed to hold our main() function. On line 2, we start the function definition of the main() function. This is where program execution starts when the program is run. The first two lines in this example needs to be present in practically every Java program we will write, but the contents of main() may change. This means that as long as we have the first two lines in place, we can write procedural code inside main, much like Python. On line 4, we output «Hello World!».
We'll immediately notice a couple of things different from Python:
- There's a lot more code. This is a typical difference between Java and Python: In Python, the interpreter generally understands what
you want, whereas in Java, you have to be more specific.
- We use curly braces ( { and } ) to open and close code blocks, and semicolon at the end of each statement. This is in correspondance with Java being a more strictly typed language.
- We define a class even if we will just print a string. In Java, all the code is organized into classes, and interaction between classes plays a vital role in code design.
- There are a lot of keywords. We will get back to these later: For now, you only need to know that they need to be there. Similarly, there are type declarations wherever there is a variable or functions involved: We will take a closer look at types shortly.
[edit] Use the source, Luke!
In order to run this example program, we need to compile it. To compile the program, we need a Java compiler. The compiler runs through the source code and converts it to Java bytecode, which can then be run on a Java Virtual Machine. Assuming there already is a compiler installed on the system you use, you will need to make sure that the CLASSPATH is set correctly. Note: on computers at the university, the classpath should already be set correctly. When the compiler is properly set up with a valid CLASSPATH, you give the following command at the console:
> javac HelloWorld.java
This will invoke the Java compiler on the HelloWorld.java source file. The output of the compile operation is one or more class files, each containing the compiled source for one specific class. For our HelloWorld example, the output will be a file called HelloWorld.class. To run this class file:
> java Hello
This will find the Hello class in any of the directories specified in the CLASSPATH, and run it through the Java Virtual Machine. Note that the class given to the java executable should be the one declaring the main() function, in case we have other classes.
These steps, known as the compilation cycle will have to be repeated each time we change something in the source code.
[edit] The advantages of compiled programs
Compiled programs:
- run faster, because the execution does not have to wait for an interpreter.
- can be run on platforms without any development tools, whereas interpreted programs need the interpreter to run.
- are sometimes easier to debug, because of the compile-time error checking performed by the compiler.
[edit] Not my type
As we saw earlier, Java explicitly declare types. Unlike Python, which is dynamically typed, Java is statically typed. This means that in Python, an object may change its type, whereas in Java, an int is born an int, lives its entire life as an int, and dies (in programming, this is called going out of scope) as an int. How do we make sure a variable is an int? We declare it to be an int when we define the variable. We do that by writing the type identifier in front of the variable name. Java (and many of the other more powerful languages, like C++) is strongly typed to mitigate the chance of the programmer doing anything he doesn't intend to, like overwriting an earlier variable. So, what does this mean when we are coding? Let us look at an example:
[edit] Code analysisThis program shows a summary of the built-in types, and also shows how to create them. As you see, you have to explicitly declare the type of each variable. Note on line 8 that an integer normally is interpreted to be an int -- to get a long, we explicitly declare it, by appending an L to the number. The same applies to floats: They are normally interpreted as doubles, and single-precision floats need to be declared with a trailing f. Also note, on line 13, that characters (chars) are declared using single quotes -- double quotes are interpreted as a String. This means that the statement on line 14 is illegal, because a char cannot hold a String. [edit] A comment on commentsAs you can see from this example, comments in Java are different from comments in Python. There are two different kinds of comments in Java:
[edit] Flow control statements: Going with the flowFlow control statements in Java are similar to those in Python, with a few exceptions. if, and while work exactly the same way, although with a slightly different syntax. The for statement in Java is somewhat different from that in Python, and Java also have two additional flow control statements. Let us start by looking at those we already know. [edit] Code analysisOn lines 4 and 5 we declare x and y to be two integers, and initialize them to 5 and 6, respectively. On line 7, they are tested against eachother, and on lines 8 and 10, various actions are taken depending on the outcome of the test. On line 13, we reset x to 0. Note that we now do not need to declare x to be an int: That was done on line 4, and we are working on the same x. The while-loop starting on line 15 is fairly straightforward: While x is less than 10, print its value and increment. [edit] The Java for-loopIn Python, for-loops are normally used to iterate over a list of items. They work much the same in Java, but in its most basic form, the for-loop iterates over a set of numbers, rather than a list. In Java, it consists of four parts, any of which are optional:
for (INITALIZATION; CONDITION; INCREMENTING STATEMENT) {
STATEMENTS;
}
Typically, you initialize a variable in the first section, see if some condition is true in the second section, increment the variable in the third section and perform one or more actions in the fourth section. Note: A for-loop does not need to iterate over a set of numbers. Basically, what a for-loop does is: Execute the INITIALIZATION-statement once before entering the loop, execute the CONDITION-code each time through the loop and break out of the loop if it evaluates to false, and then execute the statements inside the code block. At the end of each pass through the loop, the INCREMENTING STATEMENT is performed. Taking advantage of this, the for-loop can become a very versatile tool, but we will not spend more time studying that here. An example of an ordinary for-loop is in its place:
[edit] Code analysisMost of the action is on line 4: First, i is declared to be an integer with value 0. For each pass through the loop, i is tested to see if it is less than 10: if it is, another iteration through the loop is made. During each pass, the current value of i is printed, on line 5. After each pass, the value of i is incremented by one, using the increment operator ++. We will examine ++ in more detail later. As I mentioned, any part of the for-loop may be left out, and this is demonstrated on line 9. No initialization, condition testing or incrementation is performed, which means that the loop will never end. Writing an endless loop with an empty for is often called a forever-loop. In the section regarding container constructs, we will look at another kind of for loop in Java, which is quite similar to the Python for loop. [edit] The do...while-loopThe first of the non-Python flow control constructs we will take a look at is the do...while-loop. This is basically a while-loop which ensures at least one iteration through the loop. We go straight to the code:
[edit] Code analysisThe do...while starts on line 5. Anything inside the do { and }-brackets is performed at least once. Then, after it has been performed the first time, the while-condition is tested on line 8. At this point, x is 1, which obviously is not more than 5, and so execution stops. [edit] The switch-statementThe second construct we do not know from Python is the switch. This is not a loop, but essentially a compound if-statement. The switch takes an expression that can be evaluated to an int, and tests its value against the specified cases. If it finds a match, the code from that case is then executed. This is best illustrated by code:
[edit] Code analysisTo make the example a little more interesting, we read one int as input from the user. To do this, we must import the corresponding library, which is done on line 1. Lines 6 and 7 handle the actual input -- we will get back to input/output later. On line 9, the x is evaluated, and the appropriate case is chosen accordingly. If the user input is neither 1, 2 or 3, the default-branch is chosen instead. The perceptive reader will notice that for case 3, there is no trailing break-statement. What does this mean? We know break from Python, and we know that it causes execution of code to continue right after the flow control statement. In a switch, the code enters at the first possible match, and then exits once it encounters a break. If it never encounters a break, it will run through to the end of the switch. In other words, if the user enters 3 as input, both the case 3 and the default blocks will be executed! For this program, this is a (deliberate) bug, but this behaviour can be useful in certain cases. [edit] Missing in Java
[edit] A word on styleIn many programming languages, there exists holy wars regarding how to represent code. Should class names begin with capital letters? How should the code be indented? Where should we put the curly braces? Fortunately, there are official Java guidelines regarding code style. Some of these are:
if (someThing) {
// ...
}
A few other general rules:
[edit] Operators in JavaOperators in Java are much like operators in Python. However, Python uses lexical operators, i.e. and, or etc. wherever it makes sense, whereas Java uses symbols instead. The following table shows the differences between Java and Python:
All arithmetic operators not listed here, like +, -, +=, -= etc., are the same in the two languages. [edit] The pre- and post-increment and -decrement operatorsIn the example with the for-loop, we looked at the increment-operator, which increments a variable by one. There are several versions of this operator:
The following code illustrates this:
[edit] Input / OutputWe have already seen how to output simple text, and in the switch example we got a preview of how to get input. Let us take a closer look at how input and output works. [edit] OutputOutput is achieved using the System.out.println(output) function call. This prints output to stdout, i.e. usually the screen/terminal, and appends a trailing newline. If we do not want the trailing newline, we would use System.out.print() instead. Also, if we want to write to stderr, we would use the System.err.println() and System.err.print() functions. What are the differences between stdout and stderr? stdout is the standard output stream, and we write to stdout whenever we want to output text under normal circumstances. stdout is buffered, which means that writing to the terminal window, or whatever stdout is connected to, is more efficient. However, in case something goes wrong, and we want to print an error message, we want to use stderr, which is the standard error output stream. stderr is not buffered, which means that the error message we write is written to the terminal right away. If stdout is used for outputting error messages, you risk that the text gets lost in the buffer in case of premature termination of the program. [edit] InputIn order to read input from stdin (usually the keyboard), we have to create an object that is responsible for reading input. In order to read from a file, we only need to supply the URL to the file in question to the constructor of the In-object. Remember that Java is statically typed, so if we want to get an int from the user, we have to ask our input object to return an object of type int. The functions/types supported by our In object are:
This should be fairly straightforward, but let us take a look at a quick example.
[edit] Code analysisOn line 1, we import the easyIO library. This needs to be present whenever we want to use In or Out objects. We initialize our first In object on line 5 with a call to new. We will get back to new in the section regarding classes. Note that the function call after new is a call to In's constructor. This is equivalent to the call to file's constructor on line 9 of the Python code. However, since we do not specify a file name in the call to In's constructor, we read from stdin instead of a file. On line 8, we ask for a new int by calling In.inInt(). If we wanted a double or char instead, we would have replaced inInt() with the corresponding function from the table above. An Out object is created on line 16, and is used on lines 17-19. Note the various calls to out() and outln() depending on whether or not we want a newline character. We could also manually output one, using "\n". On line 20, we close the file pointed to by the Out object. [edit] FunctionsIt is time to learn about functions. In Java, all the code we write is encapsulated within a class. This means that we do not have any code that does not belong to a class, and functions are no exception from this rule. In other words, all functions in Java are member functions, or methods. However, functions local to a class, ie. functions that are member functions to this particular class, work almost like global functions (non-method functions) in Python. A function in Java consists of a few more identifying keywords than in Python. The most notable difference is that Java functions must specify a return type, and the returned object must be of that type. The same goes for arguments: Their type must be specified. Let us take a quick look at a function definition in Java.
This is a function called myFunction, which takes two arguments of type int, and returns void. void is another way of saying that the function does not return anything. void is therefore much like None in Python. [edit] Access modifiersBecause of the encapsulation in Java, not all functions are globally visible. Some functions are designed to work "behind the curtains", and should not directly be used by the user of the class or function. Because of this, Java has what is called access modifiers. These specify who should see and be allowed to use a function. public means that everyone, both inside and outside of the class should have access to the function. In Python, all functions, methods and variables are public. The private keyword means that only members of the class are allowed to use a function or variable. In addition, there is another keyword that we will not be using in this course: protected means that only members of this class and subclasses of this class may see and use members and functions. [edit] ClassesIt's time for the core part of the Java language: Classes. Everything we write will be in a class, and knowing how classes work is crucial for writing good code. Classes in Java work much the same as classes in Python: They have constructors, they have member variables, they have methods, and so on. Let us begin with a simple class:
[edit] Code analysisThe code should be pretty straightforward, but there are a few things worth mentioning. First of all, note on lines 2 and 3 how member variables are explicitly declared in the class, and not in the constructor, rather than just showing up when we want to use it. This may seem like extra work, but it actually has several advantages. By explicitly declaring variables, we know which variables are members of the class, and what type they have. We know where to look for comments regarding their use, and most important: We know that they are there. A somewhat common error in Python is to have some kind of if-statement in the constructor that prevents some variable to be created, or failing to initialize a variable we need initialized, and then attempting to use the variable later in the class. With this explicit declaration of variables, we mitigate the chances of such errors. Note that the constructor in Java is called the same as the class, and does not return any values. (public is an access modifier, as discussed earlier, and is not a return type). Also, note that in Java, self is called this, and unlike Python, we do not need to explicitly write this unless there is ambiguity. In the constructor, on lines 6-9, the two parameters passed have the same names as the member variables, and so we need to explicitly identify the member variables with this when we want to refer to them. In the print() function on lines 11-14 there are no other brands or modelYears, so we do not need to explicitly state this. [edit] Creating and using classes -- are you 'new' to 'this'?To use a class, we have to create an instance of the class -- an object to work on. This is achieved using the new keyword, followed by a call to one of the class' constructors. Once we have done this, we can use the new object as we wish. Let us create a car:
[edit] Function overloadingUnlike Python, Java does not allow you to specify default values of function parameters. Instead, there is a feature knows as function overloading, which allows us to achieve the same, as well as a few other handy tricks. Function overloading means that we create several versions of the same function, where the function signature of each version must differ. The function signature is the function name, as well as its types and number of arguments. The return value is not a part of the function signature. This means that we may have two functions with the same name, as long as they have different number and/or types of parameters. For instance, consider a class GuestList, which contains a list of guests at a given event. When working with such a GuestList, we may want to invite another guest, or we might invite another group of guests. This means that we will probably need at least two functions for adding guests: One to handle a single guest, and one to handle a group of guests. Let us have a look at an example of such a GuestList.
[edit] Code analysisMost of the code is pretty straightforward - or omitted. Note that we have two add() functions. The first version operates on a single guest, the second on a group of guests. (class Guest is irrelevant to the code we write in GuestList, and its definition is omitted). When GuestList.add(argument) is called, the compiler evaluates argument's type. If its type is Guest, the code for the first add() function is executed, if its type is GuestList the second add() method is executed, and if it is neither, an error will be raised. Function overloading can, as mentioned, be used to simulate default parameters. Consider a class for representing a Rubik's Cube. A Rubik's Cube typically consists of 3x3x3 coloured squares. Sometimes you want to kick it up a notch and play with a 4x4x4 cube instead (often called Rubik's Revenge). Such a class would have a constructor which created a 3x3x3 cube by default, but could have the ability to create a 4x4x4 cube when asked to do so. The following code illustrates how this would be solved:
[edit] Code analysisThe default constructor is defined on lines 5-9. It handles the usual case, when someone wishes to create an ordinary Rubik's Cube. Should someone want to create a larger or smaller cube, they pass the size to the constructor -- in that case, the second constructor is called. [edit] Static methods and variablesIn our declarations of main(), we have been using public static void main(). Both public and void has been explained, but we have not yet looked at what static means. A static method or variable is one that is defined for the class as a type, rather than objects of that type. In other words, we do not need a specific object of that class to call the method -- we can call the method directly. Technically, this is achieved by not passing the this argument to static methods. This implies that static methods may not access any non-static member variables. Let us look at an example.
[edit] Code analysisThe Car class is defined on lines 1 to 11. On line 2, we declare a static variable, to hold the global number of cars, i.e. the number of Car objects. In the constructor, on line 5, this variable is incremented each time a new Car is made. The function defined on lines 8 to 11 returns this number. Note the way this function gives access to a private variable. Such functions are common in Java, and other languages with access modifiers, and are called accessor functions. Their use is to ensure proper access to hidden variables. The class on lines 13-20 is created in order to show an example run of the Car class. On lines 15, 17 and 19, we print the number of cars. Note that to print the number of cars, we call Car.numCars(); rather than c1.numCars() or c2.numCars() -- we call the method from the class rather than from an instance of the class. At first, we do not have any Cars, so 0 is printed. Then we create a Car, which means that the counter is incremented, so that when we print the number of Cars again, the number is now 1. [edit] Container constructsWe often want to operate on a list or series of objects, rather than just single instances. In Python, there are several built-in constructs for performing these tasks: dictionaries, lists, tuples, etc. In Java, there is only one built-in feature -- arrays -- to help us achieve this, and arrays have several limitations. Fortunately there are also a few classes that come with the standard library. We'll take a look at a small selection of these shortly, but we will start with a closer look at arrays. [edit] ArraysArrays are Java's built-in counterpart to Python's lists. However, there are some significant differences between lists and arrays:
There are two ways of creating an array. The first, and easiest way, is to simply define all the values it should contain. The second way is to use the new keyword and specify how large the array should be. Note that if you use latter method for non-built-in types, each position in the array is not initialized. In other words, every element is the special value null (corresponding to None in Python). For built-in types, each position is initialized to 0. Let us take a look at a few examples of how to create an array:
As mentioned, an array has constant length. This means that primes can never hold more than ten elements, and each element has to be of type int. The same goes for the rest of the arrays, but note that even though heroes can never hold more than five Strings, the length of each String may vary. If an array is of limited size, what do we do if we want to add more elements? What if another hero comes along? The answer is to create a new array, that can hold more elements, and then copy the elements of the smaller array into the larger one. Note that even though we can never put more elements into an array, we are not required to use every element -- null is a perfectly good value. This means that if it is likely that we will need more elements, we should create the array a little larger than we really need:
[edit] Code analysisOn the first line, we create an array of Strings that can hold ten elements, but only uses the first five. On the second line, we use indexing to access the first unused element and set it to be a new hero. We can do the same if we create the array using new. The following example illustrates:
[edit] Code analysisOn line 1, an empty array that can hold ten Strings is created. The array is initialised on lines 3-5, using the fictive function getNextHero(). Note that i is created outside the for loop, because we want to be able to access it after the loop is finished. If we had declared i inside the loop, it would have gone out of scope when execution breaks out of the loop. On line 6, we use i to access the first empty index and store a new hero in it. After both examples the values in the array would be: "Rincewind", "Vimes", "Zaphod", "Weatherwax", "Slartibartfast", "Hrun the Barbarian", null, null, null, null
[edit] Code analysisOn line 1, we create an empty class Guest to represent a guest. The details of Guest are in any case irrelevant for GuestList. On lines 4 and 5, the two member variables of GuestList are declared: One array of Guests that holds the actual data, and an integer, numElements, for keeping track of how many Guests there are on the list. The reason for having a variable like numElements is that the size of the array does not tell us how much of that array we really use -- that is the task of numElements. This means that the number of free spaces in the array is repr.length - numElements. We define two constructors for GuestList, one on lines 7-9 and one on lines 11-13. The former takes no argument, and initialises the array to hold 50 Guests. The latter takes one argument, the number of Guests, and allocates memory for repr to hold this many elements. We have defined two functions for adding elements to our GuestList -- one function for adding a single Guest, defined on lines 15-26, and another for adding another GuestList, defined on lines 28-47. The first add()-function first tests if the array is full by comparing the number of elements to the maximum number of elements. If the array is full, it creates a new array of Guests, tmp, which is 50% larger than the previous array. It then copies each element from the previous array into the new one, before assigning the new array to be the array used as representation. On line 25, several things happen. We use indexing to access the first unused array element - because 0 is the first index, numElements is the last used element plus one. Because we use the post-increment operator, the value of numElements is first evaluated, and then incremented. The unused array element is then set to point to the Guest we are adding to the list. Note that because of the post-increment operator, line 25 could have been written as repr[numElements] = g; numElements += 1; The second add() function does basically the same as the first, only that it operates on a range of new elements. First it tests if we can fit both the used elements in this.repr and the used elements in rhs.repr (rhs for right hand side) into repr. If not, the new array is created with capacity to hold both arrays, plus a small buffer, before the current representation is copied into this new array. Then this new array is set to be the representation used by the GuestList, before the elements of the other array are copied as well. Finally, numElements is updated properly with the number of added elements. Note that in both functions, the size of the new array has been larger than it really had to. This is because creating a new array and copying elements is a relatively time-consuming task at runtime, and so we want to make sure that we only have to do it now and then. [edit] Array Summary
[edit] A New Kind of for LoopIn Java, there is a kind of for loop very similar to the for loop we know from Python. This loop is used to iterate over elements of a known type, for example an array. Let's go straight to the code:
[edit] Code analysisOn line 3, we create an array of Strings. On line 4, the for loop begins. h, of type String, is our counting variable, and for each iteration it is set to the next element in heroes. On line 5, h is printed. The result of the for loop is that each element in heroes is printed. [edit] HashMapsIn Python, a dictionary, or dict, is a container type containing a set of unique keys, where each key has a value associated with it. In Java, such a data type is called a HashMap. Unlike the Python dict, the Java HashMap is not a built-in type, but is instead a part of the Java standard library. To access a HashMap, we need to import java.util.HashMap. A HashMap is created the usual way, by using new. There are a series of methods used to operate on a HashMap, as described in the following table:
You may wonder what a Set or a Collection is. Interested readers may read more about Sets and Collections at the official Java API specification. All we really need to know is that both Sets and Collections are iterable, and that we can use iterators over them. [edit] IteratorsSo what is an Iterator? An iterator is an auxiliary class used to iterate over a series of elements. An Iterator has two methods we use to achieve this: next(), which gives us access to the next element, and hasNext(), which returns true if there is one such element, otherwise it returns false. To get an Iterator from a Set or Collection, we use the iterator() method. [edit] HashMap and types part one: CastingA HashMap is inhomogeneous, which means that it may contain objects of different types. However, Java needs to know the type of the objects it operates on. This requires us to cast the return value of functions such as get(). This is achieved by prefixing an expression with a type name enclosed in parentheses. This is similar to changing a numerical type to float in Python in order to avoid integer division. Let us have a look at an example illustrating the use of a HashMap, the use of iterators on the map, and casting.
[edit] Code analysisOn lines 6-12 the HashMap is created and filled with six book/author pairs. On line 16, the author of someBook is read from the map. Note that we have to cast the return type of get() before assigning it to someAuthor. On line 17, someAuthor is tested: If it is null, we have not stored the author of someBook. If it isn't null, the author is printed on lines 20 and 21. Lines 24-28 achieves the same as the previous block, but in less code. On line 25 we check if the map contains the key described by the variable someBook. If it does, we print the author, using the key. The entire HashMap is printed on lines 30-36. To print each key/value pair, we first get an Iterator to iterate over the keys. We then use those keys to access the value associated with each key. On line 40, the value associated with "101 Uses for a Dead Cat" is changed, and on line 43 the key/value pair whose key is "The Design and Evolution of C++" is removed. Finally, we print the size of the HashMap, and then empty it. [edit] HashMap and types part two: Locking the HashMapIf we want our HashMap to be homogeneous, i.e. to make sure that all keys and all values have the same type, we can lock it. This is achieved by appending the desired types enclosed in brackets to HashMap when we create it. If a locked HashMap is fed a key/value pair of the wrong type, a compiler error is generated. By locking a HashMap we also allow users of the map to use the Python-like for loop on the values or keys of the map. Let us look at an example of a locked HashMap, and a for loop iteration over it:
[edit] Code analysisThe code should be fairly straightforward. On lines 6-10 a HashMap of String/String pairs is created and filled. Line 11 illustrates illegal code: We cannot add an int/String pair to the locked map. On lines 13-16 we iterate over the values of the map using the special for loop, and print each one of them. [edit] HashMap Summary
[edit] String theoryWorking with text is a common task in most computer programs. We usually need to output text, read text, manipulate the text, format the text, etc. To simplify these operations, we have the String class which represents a string of text. As in Python, a String is just a series of characters, with methods to operate on these characters. Note that Strings are immutable: They cannot be changed. Changes to a String are returned as a new String object.
(For a complete description, look at the Java API specification for String.) We will take a closer look at these methods through a series of examples.
[edit] Code analysisWe define three Strings. On the first line, we create a String to hold the text we work on. On the second line, we create a new String from the substring from index 5 to index 17. On the third line, we create a new String from the substring from index 50 and to the end of text. The value of chuck will be "Chuck Norris", and the value of water will be "Water gets Chuck Norris.".
[edit] Code analysisOn line 1, a String with value "Jason" is created. This is tested against "Jason" on line 2. On line 4, a String holding a text is created. Line 5 prints whether or not it starts with "quidquid", which is false, because of the lower-case q in the parameter. Line 6 prints whether or not text ends with "viditur.", which is true. [edit] Exercises(The numbers in parentheses are the exercise numbers from Langtangen's Elements of Computer Programming.) 1 (1.2):
2:
3 (2.1):
4 (2.2):
5 (2.10):
6 (2.15):
7 (2.16):
8 (8.4):
9 (9.31):
// Make a hat with balls of 3 colours, each colour appearing on 4 balls:
String[] colours = { "red", "white", "blue" };
Hat h = new Hat(colours, 4);
// Draw a random ball
h.draw();
Exercises from Rett på Java:
[edit] Further reading
|

