Class 4 — Wednesday, September 2
Fraction becomes a Number — the zero guard, final, and both of you push.
Sections 1 and 2 are on your own machine. From section 3 you are in pairs.
- Make a repository of your own —
java-scratch, one file, one push - Predict, then run — two
xs in one constructor; write your prediction down first - The zero guard — a
Fractionthat cannot be built wrong final, and the bug on purpose — the compile error Monday never gave us- Both of you push — one machine, two repositories
Fractionis aNumber— the graded part, after the break
1. A repository of your own
A1 and A2 were made for you. This one you make yourself — the same motion as A0, except this repo holds Java and has to be open on your machine.
Either order works, and IntelliJ IDEA can do the whole thing. Starting from GitHub:
- On GitHub, click New and create a repository called
java-scratch. Public or private — it does not matter, do not spend time on it. - Open it on your own machine:
git clone <url>, or Get from VCS on IDEA’s welcome screen.
Or starting from IDEA: make a project called java-scratch, then Git → GitHub → Share Project on GitHub, which creates the repository and pushes to it in one step.
Either way, add one file Point.java holding the code in section 2, then commit and push. Do not edit files in the browser — a file edited on github.com exists only there, and nothing on your machine can compile it.
Done looks like: java-scratch on GitHub showing one commit that contains Point.java, and the same files open on your machine.
While you are here, accept the A2 invite from Discord as well, even though you will not open it until section 3. Both partners need to have accepted it — otherwise there is nowhere to put your work at the end of class.
2. Predict, then run: which x is which?
Write down what you think this prints before you run it.
public class Point {
private int x;
public Point(int x) {
x = x;
}
public static void main(String[] args) {
Point p = new Point(7);
System.out.println(p.x);
}
}Run it.
If the output is not what you predicted, that is the interesting case. Open this once you have run it, not before.
In x = x; both names are the parameter. The assignment copies the parameter onto itself, and the field is never touched — so it keeps the value Java gave it, which for an int is 0.
this.x is not decoration. It is the only way to say which x you mean.
This is the same bug we are about to find in Fraction, and in section 4 you will type it again on purpose.
3. The zero guard
Pair up now: one machine, and whoever typed least on Monday drives. You swap after the break — the same person drives sections 3 to 5, and the other one drives section 6. Open your A2 repo on the driver’s machine — git clone, or Get from VCS in IDEA.
FractionTest first, and watch it fail
Do this before you change a line. It must stop at the zero denominator.
If it passes, assertions are off and the test checked nothing. Put -ea in the run configuration’s VM options and run it again.
javac -d out src/*.java
java -ea -cp out FractionTest
Before you type the fix, answer this between the two of you: what is the one thing that has to be true about every Fraction for any method on it to mean anything? That is the promise the constructor is about to start keeping.
Then write the guard in the two-argument constructor:
if (den == 0) {
throw new IllegalArgumentException("denominator must not be zero");
}Run the tests again. They will now fail somewhere else, and that is not a regression — each failure names the next thing to do.
4. final, and typing the bug on purpose
Make both fields final:
private final int num;
private final int den;Now break the constructor deliberately: change this.num = num; to num = num;, and compile.
It refuses. Read where the error points. javac blames the closing brace of the constructor rather than the line you changed, and it mentions only num even though den has exactly the same problem. Put the this. back once you have read it.
That is the point of this block: on Monday, Java watched us write that line and said nothing.
You now have two different protections, and it is worth seeing that they are different. The zero guard makes an invalid Fraction impossible to build. final makes one impossible to become invalid afterwards. An object that cannot change after it is constructed is called immutable — String is one, and you have used it for years without noticing.
5. Both of you push
One machine means one login, so only one of you can push from that seat. The other still needs the code in their own repo.
- Whoever is driving commits and pushes.
- Attach
src/Fraction.javain a Discord DM to your partner. Attach the file — do not paste the text. - Your partner drops it into their own clone, at their own machine, and pushes.
Only Fraction.java moves; FractionTest.java is already in both repos and you have not touched it.
You wrote this together and you both push it — that is intended. Everything after today is your own work.
6. Part 2 — Fraction is a Number
Swap now — whoever navigated through sections 3 to 5 takes the keyboard.
This part is graded: it is Part 2 of A2, and the goal is to finish it before you leave rather than over the weekend.
public class Fraction extends Number {That will not compile until all four of doubleValue(), floatValue(), longValue() and intValue() exist. The compiler names them one at a time and in that order, so compile after each one. The first it asks for you already wrote on Monday under a different name — rename it and the error moves on.
The single design decision is what intValue() should do with 3/2; A2 Part 2 spells out the answer and asks you to predict -3/2 before running it.
When it compiles, run this:
Number[] nums = { 1, 2.5, new Fraction(1, 2) };
for (Number n : nums) {
System.out.println(n.doubleValue());
}Done looks like: that loop printing three numbers, one of them from your own Fraction — and both of you have pushed.