3.4 Lab: Expressions and Operators
Prerequisites: First three pages of this chapter
Estimated time: 40 minutes
Exercise environment: JDK 17+ and Bash; all files written to a temporary directory
You are ready to continue when: You can predict and verify four boundary cases, and record the reasons for any failures
chapter3_lab_root=$(mktemp -d)
readonly chapter3_lab_root
mkdir -p "$chapter3_lab_root/chapter03-lab/out"
cd "$chapter3_lab_root/chapter03-lab"Required Exercise 1: Division and Remainders
Save as DivisionLab.java:
public class DivisionLab {
public static void main(String[] args) {
System.out.println(10 / 3);
System.out.println(-10 / 3);
System.out.println(10 / 3.0);
System.out.println(-7 % 3);
System.out.println(Math.floorMod(-7, 3));
}
}javac -d out DivisionLab.java
java -cp out DivisionLabExpected output:
3
-3
3.3333333333333335
-1
2Write one sentence each explaining the rules for negative numbers for / and %.
Required Exercise 2: Assignment, Promotion, and Compound Assignment
Save as AssignmentLab.java:
public class AssignmentLab {
public static void main(String[] args) {
int left;
int right;
left = right = 10;
byte level = 127;
level += 1;
System.out.println(left + "," + right);
System.out.println(level);
}
}Compile and run:
javac -d out AssignmentLab.java
java -cp out AssignmentLabExpected output:
10,10
-128Change level += 1 to level = level + 1, and confirm the compilation fails. Don't just say "syntax differs"; explain the difference between the type of the right-hand expression and implicit narrowing.
Required Exercise 3: Short-Circuiting and Non-Short-Circuiting
Save as ShortCircuitLab.java:
public class ShortCircuitLab {
static boolean mark(String label, boolean value) {
System.out.println(label);
return value;
}
public static void main(String[] args) {
boolean shortAnd = mark("A", false) && mark("B", true);
boolean fullAnd = mark("C", false) & mark("D", true);
boolean shortOr = mark("E", true) || mark("F", false);
System.out.println(shortAnd);
System.out.println(fullAnd);
System.out.println(shortOr);
}
}javac -d out ShortCircuitLab.java
java -cp out ShortCircuitLabThe output labels should be A, C, D, and E; B and F should not appear. The three results in sequence are false, false, and true.
Required Exercise 4: String Identity and Content
import java.util.Objects;
public class EqualityLab {
public static void main(String[] args) {
String left = new String("apple");
String right = new String("apple");
String missing = null;
System.out.println(left == right);
System.out.println(left.equals(right));
System.out.println(Objects.equals(missing, null));
}
}javac -d out EqualityLab.java
java -cp out EqualityLabExpected to be false, true, and true. In the record, mark each of the three comparisons separately to check identity, content, and null-safe content contract.
Optional Exercise 1: Prefix, Postfix, and Separate Side Effects
int count = 5;
int before = count++;
int after = ++count;
System.out.println(count + "," + before + "," + after);Predict first, then verify the output 7,5,7. Then read but do not mimic:
int hardToRead = count++ + ++count;Split it into named intermediate variables and write each step's count.
Optional Exercise 2: Floating-Point Comparison Contract
Choose a tolerance for each of the following three sets of values and explain your reasoning:
0.1 + 0.2 versus 0.3
1_000_000.0 versus 1_000_000.0001
1e-12 versus 2e-12A single fixed absolute threshold may not be appropriate for all three scales. Without domain-specific error requirements, there is not enough information to declare "equal."
Optional Exercise 3: Maximum
int first = 15;
int second = 8;
int third = 22;
int maxOfFirstTwo = first >= second ? first : second;
int max = maxOfFirstTwo >= third ? maxOfFirstTwo : third;
System.out.println(max);The result should be 22. Here, two named steps are used to avoid nested ternaries that can make the branch relationships unclear. In real engineering, you can also use Math.max.
Fault Experiment
Place the three groups of code into main separately, opening only one group at a time:
// int divisionByZero = 1 / 0;
// byte left = 10;
// byte right = 20;
// byte invalid = left + right;
// boolean wrong = 1;The first group compiles; when the program reaches the integer division by zero expression, it throws ArithmeticException. The other two groups are rejected by the compiler: the sum of the two byte variables results in int, and Java does not allow replacing boolean with an integer.
You cannot simplify the second group to byte invalid = (byte) 10 + (byte) 20;. The right side of that line is a value of 30 at compile time, falling within the byte range, so the assignment conversion is allowed to compile. Record both the runtime exception and the two compile-time diagnostics separately, and do not mix the failure stages together.
Safe Cleanup
pwd
test ! -e out || rm -r -- outConfirm that the current directory is this experiment directory and delete only the out related to this experiment.
Acceptance and Cleanup
Confirm that you have actually observed integer division with positive and negative numbers, compound assignment narrowing, short-circuiting and non-short-circuiting, and string identity and content comparison. After saving the necessary experimental records, clean up:
cd
ls -ld -- "$chapter3_lab_root"
rm -r -- "$chapter3_lab_root"The next chapter will make boolean results truly control the path.