The main development environment in this course will be IntelliJ IDEA 6.0, a very nice integrated development environment that provides support for programming rather than building GUIs. We strongly recommend that everyone uses IDEA -- even those of you who, like the lecturer, are long-time Emacs fans with multiple-modifier commands like C-A-\ and M-% hard-coded in your fingers. Unlike many other IDEs, IDEA is made for programmers and stays out of the way when you don't want it to interfere.
This lab is intended to allow you to get used to using IDEA. Therefore, the object-oriented concepts used in the exercises are quite simple — in fact, you should have learned these concepts before taking the course — and the exercises themselves might seem trivial. This is intentional, so that you are not distracted from learning the environment. (If you have never programmed in Java before, despite this being part of the prerequisites for taking this course, this lab may also help you get some experience with the most basic parts of Java before getting started with the main project.)
In addition to this lab, there is also an introduction to the features in IDEA available. Reading this takes a little bit of time, but should save you a lot of time in the end since you will be able to make better use of IDEA's features. Additional documentation is available from the IDEA documentation site.
This lab must be done in IDEA, and we strongly recommend that you use IDEA in the project too. The code generation and refactoring capabilities of this environment will make life a lot easier for you in the project lab, and we might require changes and refactorings to your code that are easy to do in IDEA but would take hours in Emacs.
After you have finished this lab, you are free to decide to use another environment. However, the final code you hand for your message forum project must be in the shape of a fully functional IDEA project! We will be using built-in IDEA functionality together with a number of plugins to enable us to navigate through your code more easily as well as to help assess the quality of your code.
This lab should not be handed in. Instead, you should ask a lab assistant to take a look at the finished code on screen. He might require a few improvements and changes before your code is approved.
Don't hesitate to ask the lab assistant to take a look at your code during any scheduled lab time, even if you don't have a particular question in mind. We might have suggestions that help make your code cleaner, or that might save time in the future.
If you need to ask for help, you should first check the list of common problems. This list is updated during the course, so even if your problem was not listed a couple of hours ago it may be listed now.
If you want to ask for help by e-mail, please include the course code "TDDI48" in the subject.
If your problem isn't listed and there is no lab assistant available, you can still ask for help by e-mail. In that case, please make sure that you give us all the information you can find about the problem:
If you get an error message and you need help to fix the problem, include the entire error message in your mail!
If your code throws an exception, and you need help to find out why, include the
stack trace of the exception (using the printStackTrace() method
available in all exception objects). We can't help you if you only say "when I
try to add a user, an exception is thrown"...
Make sure that you make it very clear exactly what you intended your code to do and exactly what happened instead.
...and so on. This will save time both for you and for your lab assistant.
Installing IDEA
Starting IDEA
Creating a project in IDEA
Before you use IntelliJ IDEA you must install the IDEA configuration files in your home directory. This is done only once!
~TDDI48/idea/ideaconfig6.sh
This creates a directory called .IntelliJIdea60 in your home directory and copies some configuration files to that directory.
You must also add the JDK 5.0 module:
module add prog/jdk/5.0
module initadd prog/jdk/5.0
Several versions of IDEA have been installed in parallel. New updates will be installed as they are released and will be announced on the course home page. At the time of writing, the most recent version is IDEA 6.0.4 build 6148. To start it, use the following command.
~TDDI48/idea/idea-6148/bin/idea.sh
If new versions of IDEA are installed, you may have to change this command line to reflect the new version number.
Follow these steps to create a project in IDEA. For TDDI48, you should create one IDEA project for the first lab and one IDEA project for the larger programming project.
Create a new project using . If this is the first time you start IDEA, the New Project dialog may appear automatically.
Give the project a suitable name, preferably without Swedish letters åäöÅÄÖ (just in case...), for example "Lab1".
Then tell IDEA the location where you want to save the project, for example in /home/noone123/tddi48/lab1/. You can type the path manually or press the "..." button to select a path. In the resulting dialog window, you can press the folder-with-a-star toolbar button to create a new folder.
Press .
You will be asked for a compiler output path where IDEA will place compiled classes. This could for example be "/home/noone123/tddi48/lab1/Lab1/classes/". The default value should be safe.
Press .
The next thing to specify is the JDK (Java Development Kit) to be used with your project files. Please use the newest version of JDK 1.5.x / 5.x available (at the time of writing, this should be JDK 1.5.0_10). If no version of JDK 1.5 is available, use the "+" button to add a new JSDK and select /sw/jdk-1.5.0_10 in the file dialog.
Press .
A project consists of one or more modules, which can be reused in more than one project. In this course, we will only use a single module for each project. Select "Create single-module project".
Press .
Since the first lab is not related to web applications, you will create a plain Java module, without any special web application related features. Select Java Module.
Press .
Give the module a name. You can give it the same name as the project, for example "Lab1", or you can choose another name.
Specify the content root for the module. This is the location where all the files related to the module are stored. By default, this is the same directory as the project directory. Accepting the default location is a safe choice.
A module can contain Java source files as well as other related files. In this step, IDEA wants to know where your source files are located. It is safe to accept the default, that is, to create a "src" subdirectory inside the module directory.
Press .
Shape, Circle, and RectangleIn this exercise, you will implement a few simple Java classes. We assume that you have already started IDEA and created an IDEA project as shown above.
Note again that the entire point of doing this lab is learning how to use IDEA. The end result does not matter -- we want you to explore some of the functionality available in the environment, and therefore you should make sure you actually use code generation, navigation and other features as described below. Just typing everything from scratch might get you through this tiny lab more quickly, but you won't learn as much and you will waste time during the much larger project.
First, a Shape class.
Follow the instructions below to create a class called
se.liu.ida.youremail.coursecode.lab1.Shape, where
youremail is your e-mail address (noone123) and
coursecode is TDDI48, TDDB87 or whatever course you
are currently taking.
To create a Java class (or interface) in IDEA, first determine (1) the name of
the package that should contain the class and (2) the name of the class. Right
now you want to create a class called Shape in a package named
something like se.liu.ida.noone123.tddi48.lab1.
The left-hand side of the screen should show the project pane. If it doesn't, select .
When the project pane is set to "View as: Project", you see all modules within your project (though in this course you only use one module). If you double-click a Java module (a folder icon with a blue cube), you see all the content roots for that module (in this course, there is only one content root within the module). Within this content root, you see a directory/file hierarchy. In addition to the content roots, you can also see the Java class libraries used for this module. This corresponds to the CLASSPATH for a command line system.
[-] ### Lab1 (Java module, folder with blue cube)
[-] ### Lab1 (content path: directory named "Lab1")
| | ### src (src subdirectory)
| +--### Lab1.iml (module definition file)
| +--### Lab1.ipr (project definition file)
| +--### Lab1.iws (personal workspace configuration file)
[+] ### Libraries
So why don't you see a node for the classes/ subdirectory? Because it was automatically marked as an excluded directory, since it only contains automatically generated files that do not have to be handled manually.
Since this is the first time you create a class, you don't have any packages yet. It is time to create the package that should contain your new class. Right-click the src node. The blue color of the folder indicates that this is a source path -- you can have more than one, but non-blue directories are just plain directories and are not intended to contain source code. Select to create the package, "se.liu.ida.noone123.tddi48.lab1" (with your own account name and course code, of course).
You will see the package hierarchy either as a standard directory tree or as a flattened view, where there is a single node for the package "se.liu.ida.noone123.tddi48.lab1". You can switch between these views using one of the toolbar icons in the project pane (the second one, in IDEA 6.0.4).
Now right-click the destination package (the newly created lab1 "folder") and select
New | Class to create a new class in the package.
Specify the name of the class you want to create, for example
"Shape". The full name of the class is then
"se.liu.ida.noone123.tddi48.lab1.Shape".
The class should have a constructor without arguments, Shape(),
which prints "A shape is constructed".
Position the cursor where you want the constructor (you may have to insert a few newlines). Select . Select "Constructor". An empty constructor is generated.
In the constructor, enter sout and press TAB. The
"sout" live template is automatically expanded to
System.out.println(""); and the cursor is within the quotes. Enter
the rest of the text: "A shape is constructed".
Notice the syntax highlighting. For example, IDEA knows that
System.out is a static field, and highlights it accordingly. The
highlighting can be adjusted in the settings (), if it turns out you absolutely hate the
preconfigured colors. If you do this, please save your changes as a new scheme
rather than modifying the current scheme, so that your lab assistant can switch
back while he's helping you, if it turns out he absolutely hates your modified
colors.
Try pressing
when the cursor is in System, in
out and println.
Try pressing
when the cursor is in System, in
out and println.
Also try pressing
when the cursor is in println. Ctrl-B (or
ctrl-mouse-click) navigates to the definition of an element. In this case, it
navigates to the source code for one of the overloaded println
variations in class PrintStream.
Press one or more times to return to where you were. (Your window manager may steal this key combination. If so, you can reassign it in / .
The class should also have a public abstract method void draw().
Place the cursor where you want to place the metnod. Type "public abstract void draw()" and press to "finish the statement".
Since the class is not declared abstract, public class Shape and abstract will be underwaved in red, and the little
square in the top right corner of the editor will be red. There will also be a
red error stripe in the stripe bar to the right of the scroll bar. The position
of this error stripe corresponds to the proportional position of the error
within the current source file.
Go to the first error using . You will notice a small yellow or red light bulb popping up. This is the indication that an intention action is available — an action that helps you fix an error by guessing what you meant to do. (No, this is not like the MS paperclip — the suggestions are usually useful...)
Click the light bulb or press to pop up the intention menu. You will see one entry: "Make 'Shape' abstract". Click this or press to select it. The class is now abstract.
Then, a Circle class.
Create a concrete class Circle in the same package, as a subclass
of Shape.
Create the class just like before. Add extends Shape manually.
The declaration is now underwaved in red. This is because we have not yet
implemented the abstract method in Shape. Ignore this error for
now.
The class should have three public int fields — an x coordinate, a y coordinate, and a radius.
Add these fields manually.
IDEA 4.0 and later: Depending on your code inspection settings, you may get a warning that these fields may not be initialized during object construction. Because we have not created a constructor yet, Java creates a default constructor taking no arguments, and this constructor does not initialize the three new fields. Of course this is just because we haven't gotten around to creating a constructor yet — which shows that some warnings will go away automatically if you just go on implementing the class the way you intended to.
Add a constructor with three arguments (x, y and radius), which saves the values of the arguments in the three fields and prints "A circle is constructed".
Like before, create this constructor by placing the cursor where the constructor
should be and using Code | Generate | Constructor: Alt-Insert.
Mark the fields whose values should be initialized by the constructor (click the
first, shift-click the last; using the keyboard: go to the first, press
shift-down to extend the selection downwards) and press OK. Initializers are
added automatically. Use sout to add the
printout.
Implement a concrete draw() method that prints "A circle is drawn".
To implement an abstract method, place the cursor where the method should be and use . Select the method(s) to be implemented in the dialog. Use sout again.
The third shape class is called Rectangle. Do you remember how you did
this before?
Create a concrete class Rectangle as a subclass of
Shape. The class should have four public integer fields — an x
coordinate, a y coordinate, a width, and a height.
Add a constructor with four arguments (x, y, width, and height), which saves the values in the four fields and prints "A rectangle is constructed".
Add a draw() method that prints "A rectangle is drawn".
Create another class ShapeTest, which has a main method.
Use the template psvm to create the main method.
In the main method, you should allocate a Shape[] array with 4-6
elements and fill it with circles and rectangles (created using
new).
Try using IDEA's "introduce variable" function. First, type the expression you
want: new Shape[5]. Then, use to introduce a new variable for this
expression. You can enter a name for the new variable, or just accept the
default name. Press Enter.
This function is quite useful when you want to refactor a very long expression and separate it into smaller parts. Just select a subexpression and use to introduce a variable.
Note that the new variable is highlighted. This is because it is currently unused.
Make sure you didn't just allocate the Shape[] array but that you
actually created few circles and rectangles to place in the array!
Then, iterate over all elements in the array and call their draw()
methods.
Use the itar live template to iterate over a native Java array. Select and select itar from the menu; this is another way of selecting a live template.
Now you see why it is called a live template. A number of places in
the generated code are outlined in red; these parts can be edited as part of the
template. The first one, where the cursor is, is the loop variable, which is
usually called i; try typing "index" to rename the variable. Press
TAB to reach the array over which we iterate; as you can see IDEA has correctly
identified the two arrays that are available in this scope (args
and your own array). Pressing TAB again takes you to the variable in which each
element is stored. Pressing TAB a final time deactivates the template and puts
the cursor where you want to continue typing your code.
Extend the code within the loop. If the shape is an instanceof Circle, you should also print the circle's x and y coordinates.
Start using IDEA's code completion. Type "if (sh[ctrl-space, select shape] inst[ctrl-space] Cir[ctrl-space]) {[enter]".
Try printing the value of the x field:
System.out.println("X coordinate is " + shape.x);
As you notice, you can't do this because you must first cast shape
to a Circle. Place the cursor within the word shape
and press Ctrl-W. This selects a single word; repeated invocations select
larger and larger structures, and Ctrl-Shift-W unselects one step at a time --
try it!
When you have selected shape, select and then select "((type)expr)". You will get
most likely get println(((Circle)shape).x), because IDEA analyzes
the preceding code and sees that you have just checked whether
Shape was a Circle. If IDEA was correct, you press
TAB; if it was wrong, you can select another type from the dropdown or simply
overwrite the suggested type.
Do the same thing for the y field.
What is printed when you run ShapeTest (see instructions below)? Which
methods and constructors are executed, and in which order? Make sure that you
understand why.
You can compile the entire project using , or use (Ctrl-F9) to only recompile the files that have changed and the files that depend on them.
Running a program (a class with a main() method) in IDEA requires a run configuration. You can create new run configurations in the following way:
Select . In the dialog window, press the "+" button to create a new application configuration. Give it a name, and specify a main class (use the "..." button to select a class!).
"VM parameters" are given to the Java virtual machine. Normally this box can be left empty.
"Program parameters" are the command line parameters specified for your program (given as arguments to the main() method).
The "working directory" is the directory where your program is started, and is only relevant if your program opens files relative to the current directory.
In "Use classpath and JDK of module:" you should select the module the program "belongs" to. In your case this is quite simple: You only have one module.
Click .
You can then run your program by selecting a run configuration in the drop-down menu beside the green "play" button in the toolbar, and then pressing the "play" button.
As a shortcut, you can also create a temporary run configuration for any program with a main() method, and then immediately execute this run configuration, in the following way:
Right-click the editor for the class you want to run. Select "Run MyClass.main()".
In the previous exercise, all the fields you created were public. Now you realize your mistake: They should have been private! Make them private, introduce getters for all the fields (and setters, if you want to), and make sure that you use the getters and setters wherever this is necessary.
Go to the Circle class: Select and type "Cir" (which is auto-expanded), followed by Enter.
Choose . Select the
checkboxes for x, y and radius to encapsulate
these three fields. Select Get Access to create getters, and unselect
Set Access (you do not want to create setters). Make the encapsulated
fields' visibility private, and the accessor methods' visibility public. Unselect
Use accessors even when field is accessible, so that you don't have to use
the accessors within Circle, only outside the class. Click OK/Enter.
You will get a refactoring preview, where the two uses of x and y in ShapeTest are
shown. Here you can unselect items that you don't want to change, if any. Then you
click .
Do the same thing in Rectangle. Since we never used
Rectangle's fields outside its class, the refactoring preview only
contains the fields themselves.
In this exercise, you will extend the program you wrote in Exercise 1
(Shape, Circle, Rectangle).
Create a new class Point. This class should have:
Two private integer fields, x and y.
A constructor with two arguments, x and y.
Use Generate Constructor as before.
Two accessor methods getX() and getY() that return the
x and y coordinates.
Create these methods by placing the cursor where they should be and then using (mark the fields for which you want to generate getters).
Rewrite the Circle class so that it uses a Point object instead of
the old x and y fields. The old constructor should still exist,
and should still take x and y arguments, but instead of saving
x and y directly, it should create a new Point object
that it stores in a Point field. You must also rewrite the two getters.
Rewrite the Rectangle class in the same way.
In this exercise, you will extend the program you wrote in exercise 3 by
implementing equals() and hashCode() methods for Point,
Rectangle and Circle. (If you don't know what a hash code
is, take a look at the definition in the Java Glossary.)
To generate equals() and hashCode() methods in a class, select and then select equals() and
HashCode(). Select the fields that should be included in the comparison for
equals and then for hashCode (all?).
If there are non-primitive fields (object-type fields such as the Point
field in Circle and Rectangle, then IDEA will ask you for
a set of non-null fields. A non-null field is a field whose value cannot be null,
so that IDEA does not have to insert a null check for this field. If in doubt, do
not select any non-null fields at all. In this example, though, we know that the
center of a Circle is never null (always an actual Point).
Take a close look at the methods that are generated and ensure that they are what you intended. Never trust a code generation tool completely. Always double-check what has been generated. Tools are no substitute for knowing what you're doing!
The Collections
Framework contains several list classes, for example ArrayList.
In this exercise you will create two new data structures, a Queue and a
Stack. These structures will not allow the user to add or remove inner
elements; you can only push and pop elements at the correct "end".
You can still use an ArrayList for the inner storage, however.
Create a Queue class which does not extend any class.
Add a List field: private List myList.
Since you haven't imported java.util.List, IDEA will ask you
whether you want to do so now. Press Alt-Enter to accept and choose the correct
List class (the one from java.util).
Add a constructor with no arguments, which creates an ArrayList.
If you use Generate Constructor as before, note that you should not mark any fields to be initialized by the constructor -- because the ArrayList should not be given as a parameter to the constructor, it should be created inside the constructor. Use "Select None" in the field dialog.
There are some methods from ArrayList that should be available in
Queue too. For example, the size() method should be
available in Queue. You can forward or delegate
these method calls to the Queue: Add a method public int
size() which simply returns myList.size().
The methods you should delegate to ArrayList are
size(), isEmpty(), clear(), and
contains(Object).
Select . Select the target
myList. Select the methods you want to delegate (click the first
one, ctrl-click the second, ctrl-click the third, and so on). Press OK.
Add the two new methods void push(Object obj), which adds an object
at the end of the list, and Object pop(), which both
returns and removes the first object in the list, or throws
NoSuchElementException if the list is empty.
Then write a Stack class, which is similar except that
pop(Object obj) returns and removes the last object in the
list, or throws NoSuchElementException if the list is empty.
Press F5 while visiting the Queue class to create a clone of that
class. Select Stack as the new name. Change the new class according
to the instructions above.
Finally, you should write a test program that uses your new classes. For example,
you could write a test program that adds some strings to a Queue using
push(), and then pop()s all the strings, one at a time,
and prints them to the screen. Do the same thing using a Stack.
Write a program that sorts all its command line arguments in alphabetical order and prints them to the screen.
First, create a list (ArrayList
or LinkedList)
and add all command line arguments to that list.
Then, sort the list using the static utility method Collections.sort(List
list) (as you may remember from the lectures, this method is placed in the
utility class Collections rather than in any specific list data type,
since it can be used for any List).
After typing "Collections.sort(", press ctrl-shift-space to see all items
of the appropriate type, that is, all items of type List. This is
called SmartType Completion and automatically filters out all items except those of
the correct type.
The reason for not using SmartType Completion always is that you may have to go
through an intermediate step before you reach the intended type. For example, if
you had wanted to type Collections.sort(foo.getBar().getList()), you
would have had to use Basic Completion to complete foo and
getBar(), and then you could have used SmartType Completion to complete
getList().
Finally, print the resulting list. Ask the list for an Iterator
that you use to iterate over all elements in the list.
First declare an Iterator variable, and make sure it points to the
iterator you got from the list. Then use the itit
template to actually use the iterator..
To test this program, run it with some command line parameters to sort.
Create a new run configuration as described earlier in these instructions. Add your command line parameters in the "Program parameters" field. Do not add them in "VM parameters"; those parameters are given to the Java virtual machine, not to your program.
You just realized that you don't want the x and y coordinate fields in
Point to be named x and y. Instead, they
should be named xCoord and yCoord. Rename them.
Let's suppose you were in the Circle class when you got this idea. If
you're not already there, go to Circle using Ctrl-N.
Hold down Ctrl as you move the mouse around the code. You will see tooltips showing information about the items over which the pointer is hovering.
Now ctrl-click Point in the code. You will automatically be moved to
the Point class.
In Point, go to the x field and select . Enter the new name for this field
and press Enter. IDEA will ask you whether it should also rename the getter; please
do so. After verifying that everything is correct in the refactoring preview,
select click .
Do the same thing for y.
Extend the program you wrote in exercise 3. Create a new exception type called
NegativeSizeException, subclass of Exception. Modify the
constructors of the Shape subclasses so that they throw a
NegativeSizeException if the width, height, or radius argument is
negative.
You may need to take care of potential NegativeSizeExceptions in
certain places where you create objects.
IDEA can help you write catch statements. Use Ctrl-W (maybe multiple
times) to select the code you want to surround with a try/catch
statement, and then use to generate the statement. Note that IDEA automatically
determines which exceptions can be thrown within the block you marked, and adds
catch clauses for those statements.
As always, you should test your program to make sure that it work.
That's it: You've finished the first mandatory exercise. You should now ask the lab assistant to take a look at your code. You do not have to hand it in.