This page is a bit about 'what it takes to start the SWEA course'. Not all students have followed the 'Introduction to Programming' course (Java based) in the AU computer science/it product bachelor, which contains the primary topics that SWEA is based upon.
So I will try to organize this information package as a set of recommendatations and exercises (with hints) preparing you for starting the course without being overwhelmed.
"You can express any program in any programming language." True.
"You can program any program in a language you do not know, in the same time as in a language you do know." Not true.
So if you have followed a course in Python, or is used to C#, or Go, or whatever, you can of course follow SWEA, but you should spend some time before starting SWEA to get used to Java.
Conclusion: Program some code in Java to get a bit of experience and training. I will provide some exercises below.
SWEA does not dictate choice of programming environment so you can use Emacs, BlueJ, Eclipse, or IntelliJ as development platform, but IntelliJ is the course recommended tool! And the TA's know that particular IDE.
You need a good editor and compilation system, to be efficient and spend time on the mandatory project. BlueJ is a good learning platform, but it is not sufficient for coding the kind of projects that SWEA is geared towards.
Conclusion: Spend some time developing Java using IntelliJ (if you are not already highly proficient in another professional Java IDE).
(It should be mentioned that I have actually coded all the exercises below using only a good editor (Emacs) and the standard shell based java compiler and jvm, and it suffices for these small examples, but --- it does not scale to the mandatory project.)
Below I will outline the areas of programming that we again and again base ourselves upon in SWEA.
Java is an object oriented (OO) programming language, and SWEA is rooted in this OO paradigm: we will develop classes, and create objects from these classes again and again.
I have found a number of Java basic OO tutorial videos on youtube (those that I watched were not fantastic, but well...), so if you are really rusty, try to find something there.
Once the core is in place, you can rehearse a bit on the exercises below.
Exercises:
Time24Hour mytime = new Time24Hour(8, 58); System.out.println( "The Time: " + mytime + ". Must be 08:58.");That is, there are prefixed zeroes, like "07:05". Then add a 'addMinutes()' method which allows you to add to the time respecting the normal 24 clock:
mytime.addMinutes(3); // 3 minutes added to 08:58 is 09:01 System.out.println( "Three min later: " + mytime + ". Must be 09:01.");You can make the exercise progressively harder; start out by only supporting adding up to 60 minutes, then support subtracting minutes, then support adding/subtracting multiple hours (in same day), ala
// 3 minutes added to 08:58 is 09:01 System.out.println( "Three min later: " + mytime + ". Must be 09:01."); mytime.addMinutes(-3); System.out.println( "Three min sooner: " + mytime + ". Must be 08:58."); mytime.addMinutes(180); System.out.println( "180 min later: " + mytime + ". Must be 11:58."); mytime.addMinutes(-240); System.out.println( "240 min sooner: " + mytime + ". Must be 07:58.");Alternatively, you can aim for a more general solution from the start which solves all cases.
Solutions: At the bottom of this page, you will find hints for solving these (and all the following exercises.)
A object contains state (via its instance variables) and provides methods to inspect and modify its state (via its methods).
In general, an object should shield itself from modifications that are invalid or not properly controlled.
Example: a class to represent a circle may (wrongly) look like this:
class Circle { public double radius; public double perimeter; // "omkreds" public Circle(double radius) { this.radius = radius; this.perimeter = 2 * radius * Math.PI; } }Argue why it is problematic before reading on.
Well. The radius and perimeter is linked by a well-known mathematical law, but the code above allows me to change them independently and without respecting that law, like:
Circle c = new Circle(2.0); // Perimeter = 2 * PI * 2.0 c.perimeter = 1234567.89; // Ups - not anymore
Java allows you to control access to methods and member variables, using "public" and "private" (and a few others), thus providing "encapsulation" = the object itself ensures that the law is always respected.
Exercises:
You will hear me say "Program to an interface" about five times in every lecture. Interface is both an abstract concept but also a central language concept in Java, allowing you to separate "the contract from the actual implementation". So, we will train it a lot in SWEA.
Still, it is nice that you have "seen it before". A java interface is simply 'the contract' without any implementation details. Therefore, an interface cannot contain instance variables, and it never has any method bodies, only the signatures.
Exercises: Rename the Circle class (last exercise) to CircleImpl and let it implement a Circle interface, that defines the 'contract' of a circle (=public methods only).
A lot of programs are geared around "handling large sets of data". In Java the 'util' package contains "collection classes" which are standard implementations of classic data structures like lists and maps. You should know these, and 'List' and 'Map' in particular.
Exercises:
Once you have collections, you quickly find yourself in a situation where you compute something based upon inspecting each element in the collection. This is a 'sweep' or a 'for-each-loop' or an 'iteration' - many names, same thing.
Java supports iteration in many ways, both the 'old-school' for each loop
for (Card c: cardDeck) { "do something with c" }or the Java8 streaming API (which allows a ton of cool things but is also a big topic in itself)
cardDeck.stream().forEach( c -> { "do something with c" } );
Exercises:
Large programs are ... large. Packages are a java mechanism for grouping related interfaces and classes into a folder hierarchy, so you do not have to overview 2.000 files in the same folder.
In java, a class in package "com.baerbak.minidraw" must be in a folder named "(something)/com/baerbak/minidraw". And the (something) must be in the java classpath, so the compiler and jvm knows where to find the package.
Exercises: Put the card related classes in a package 'card' and the deck related class in a package 'deck'; that is reorganize the code from the above exercise.
In OO languages, a class can inherit features of a superclass by subclassing. Abstract classes define commonality between a set of subclasses but leaves implementation details to these subclasses.
A classic example is from computer graphics that can draw/render a number of geometrical shapes: circles, rectangles, etc. Some things are commen to all shapes: they have a position on the screen, they can be moved some (dx,dy) to a new position---and other aspects are special for each shape, notably how they are drawn on screen.
In OO/Java you would declare an abstract (base)class 'Shape' with (at least) an instance variable to hold the position of the shape, and a method to move it to a new position. And then you would declare an abstract method for the 'draw' behaviour. An abstract method has no method body (just like a method declaration in an interface), it must be overridden in a subclass.
Exercises:
This section presents a bit of nudging towards a solution.
You need an instance variable for 'balance' and two methods, one for 'withdraw()' and one for 'deposit()'.
You need a 'main(String[] args)' method which is the starting point of every Java program. In this method you have to instantiate account object and manipulate them. Something like
public static void main(String[] args) { // Create an account Account henriksAccount = new Account(); System.out.println("Henrik's account balance is: " + henriksAccount.balance()); ... }
To make a object immutable, you simply do not add any 'setter' methods (i.e. there are no public methods that can change the value of the instance variables.) Set the values in the constructor instead.
An 'enum' is a rather peculiar type of class, which (usually) only contains a list of names, those names that is the range of values. Like
public enum Suit { Clubs, Diamonds, Hearts, Spades }
The names must be identifiers, so you cannot have a Rank value of "2". Circumvent it by prefixing with an underscore, like "_2".
Internally, Java treat enums as integers, and you can get that
integer by the 'ordinal()' method. Suit.Clubs.ordinal() ==
0
is a true statement.
Well, this is more of a algorithmic exercise. A naive (but fine) implementation is to have instance variables for both hour and minute. Then adding/substracting requires some use of divivion and the modulo operator. A more general approach is to only store 'total minutes since midnight' and then compute the hour and minute to display.
To ensure prefixed '0' in the toString() method you can make an 'if-statement' to handle cases where hour/minute is less than 10.
Encapsulation is well supported by Java: simply declare the instance variables 'radius' and 'perimeter' as 'private' and no outside object may alter their values.
In the setter methods, be sure to recalculate 'the other variable'. That is, in 'setRadius()' method be sure to update the perimeter according to the mathematical law.
Do not enter Pi youself. Find it in the Math package in Java's standard libraries.
Call the circle class for 'CircleImpl' and let it implement the 'Circle' interface which only lists the public methods.
Remember to declare the List using Card as generic type,
ala List<Card>
, and use a concrete
implementation (like ArrayList
) for the actual
type.
List have a lot of different methods for manipulating the list, for the exercises given, you should look for methods 'add()', 'get()', and 'remove()'.
To initialize the deck, you can use a nested iteration (two
for-loops), that each runs over all elements in the suit and
rank. To get the set of values in an enum,
use Suit.values()
etc.
Regard shuffling, search the www for Fisher-Yates algorithm.
Remember, putting a class A into package 'dk.au.cs' requires three things: a package statement in A, import statements in consuming classes, and respecting that class A must be in a specific folder.
The visibility 'protected' can be used to give access to an instance variable in all subclasses but not "outside" classes, that is, something like "public" for subclasses but "private" for other classes. So that makes sense for a 'position' instance variable.
As stated, Java has the 'java.awt.Point' class which encapsulate a (x,y) point, so you can use that to store position in the shape.
The method Point.translate(dx,dy) can be used to "move" a point.
This section presents much more nudging towards a solution.
A class is declared like this
public class Account { (stuff here) }and must be in a class named
Account.java
. Classes begin with capital
letters in Java.
Instance variables in the class holds the object's internal state. You declare them by specifying the type like
private int balance;
A class should have a constructor, a special method that initializes the object. The constructor has the same name as the class, but no return type like:
public Account() { balance = 0; }
Methods are the things we can ask our object to do. You declare a method header and provide the implementation of that method.
public void deposit(int amount) { balance += amount; }
No further hints.
A short if form is something like
String hourAsString = (hour < 10) ? "0"+hour : ""+hour;
To do formatting with prefixed 0 you can actually use the 'format' method of String. Have a look at that...
Something like
public class Circle { private double radius; private double perimeter; ...
Make the 'adjustment' into a private method, so you can call it from both the constructor and the set method.
public Circle(double radius) { this.radius = radius; adjustPerimeter(); } private void adjustPerimeter() { this.perimeter = 2 * radius * Math.PI; }
The interface may look like
public interface Circle { double getRadius(); double getPerimeter(); void setRadius(double newValue); }
Note that you do not need to specify 'public' on methods as they are by definition public. (But you can do it without Java complaining.)
You could try to solve the iteration exercises with both the classic for-loop, or with the streaming API.
For instance, counting the number of cards in the deck having a given 'rank' can be done via 'filter' and 'sum':
return theDeck .stream() .filter( c -> c.getRank() == rank ) .sum();
And shuffling? The Java collection library already has it.
Collections.shuffle(theDeck);Morale: Never implement anything unless you can not found it in trust-worthy libraries!
To state a class, A, is in a package, start the .java file with "package dk.au.cs" or whatever package it belongs to.
To import it in consuming classes use "import dk.au.cs.A" or the more lazy "import dk.au.cs.*" to fetch all classes in that package.
An abstract class is declared as any other class, but you prefix
it with public abstract class Shape
. Methods and
instance variables are declared as you normally would. The
'draw()' method should be declared abstract as
well: public abstract void draw()
.
Below you can find a Zip file with my own proposals for solving the exercises. Note that programming is not like math: there is no such thing as the one correct solution. There are several solutions possible, so just take mine as inspiration. In several places you will find code commented out, representing alternative ways of doing this or that.
Find my proposals for solving the exercises in this zip file: prereq-proposals.zip.
- Henrik Bærbak Christensen