5.8 Lab: Methods, Pass-by-Value, and Overloading
Prerequisites: Method declarations, parameters, return values, call stacks, and overloading
Estimated time: 50 minutes
Practice environment: JDK 17+ and Bash; all files stay in a temporary directory
You are ready to continue when: You have completed four required experiments and explain the call contract
chapter5_lab_root=$(mktemp -d)
readonly chapter5_lab_root
mkdir -p "$chapter5_lab_root/chapter05-lab/out"
cd "$chapter5_lab_root/chapter05-lab"Required Exercise 1: Pure Computation
Save as NumberTools.java:
public class NumberTools {
static boolean isEven(int value) {
return value % 2 == 0;
}
static int maxOfThree(int first, int second, int third) {
return Math.max(first, Math.max(second, third));
}
static int digitSum(int value) {
long remaining = Math.abs((long) value);
int sum = 0;
do {
sum += (int) (remaining % 10);
remaining /= 10;
} while (remaining > 0);
return sum;
}
public static void main(String[] args) {
System.out.println(isEven(-4));
System.out.println(maxOfThree(3, 9, 5));
System.out.println(digitSum(-2147483648));
}
}javac -d out NumberTools.java
java -cp out NumberToolsExpected to be true, 9, and 47. digitSum first converts to long and then takes the absolute value, avoiding the boundary where Math.abs(Integer.MIN_VALUE) remains negative.
Required Exercise 2: Demonstrate Pass-by-Value
Save as PassingLab.java:
import java.util.Arrays;
public class PassingLab {
static void changePrimitive(int value) {
value = 99;
}
static void mutateArray(int[] values) {
values[0] = 99;
}
static void replaceArray(int[] values) {
values = new int[] {7, 8};
}
public static void main(String[] args) {
int count = 1;
int[] numbers = {1, 2};
changePrimitive(count);
mutateArray(numbers);
replaceArray(numbers);
System.out.println(count);
System.out.println(Arrays.toString(numbers));
}
}javac -d out PassingLab.java
java -cp out PassingLabExpected:
1
[99, 2]Explain by stating "What values were copied, and whether the two variables identify the same object," without using the erroneous shortcut "arrays are passed by reference."
Required Exercise 3: Overload Resolution
Save as OverloadLab.java:
public class OverloadLab {
static String pick(long value) {
return "long";
}
static String pick(Integer value) {
return "Integer";
}
static String pick(int... values) {
return "varargs";
}
static String describe(Object value) {
return "object";
}
static String describe(String value) {
return "string";
}
public static void main(String[] args) {
Object value = "iron";
System.out.println(pick(1));
System.out.println(pick());
System.out.println(describe(value));
System.out.println(describe("iron"));
}
}javac -d out OverloadLab.java
java -cp out OverloadLabExpected: long, varargs, object, string. Record the static argument types at each call site and the applicable phase.
Required Exercise 4: Stack Trace
Save as TraceLab.java:
public class TraceLab {
static void loadOrder() {
parseQuantity();
}
static void parseQuantity() {
Integer.parseInt("many");
}
public static void main(String[] args) {
loadOrder();
}
}javac -d out TraceLab.java
trace_status=0
java -cp out TraceLab || trace_status=$?
test "$trace_status" -ne 0The process should exit with a non-zero status and print NumberFormatException. From parseQuantity, loadOrder to main, mark the business call chain; error messages and JDK internal frames may vary with versions.
Optional Exercise 1: Bounded Recursion
static long factorial(int value) {
if (value < 0) {
throw new IllegalArgumentException("negative value");
}
if (value > 20) {
throw new ArithmeticException("factorial exceeds long: " + value);
}
if (value <= 1) {
return 1L;
}
return Math.multiplyExact(value, factorial(value - 1));
}Test 0, 1, 5, 20, 21, and -1. The factorial of 21 exceeds long, so the input check rejects it immediately; negative values violate the input domain. Also pass Integer.MAX_VALUE and verify that it is rejected before recursion starts.
Optional Exercise 2: Consolidate Default Parameters
static String describeItem(String name) {
return describeItem(name, 1, false);
}
static String describeItem(String name, int level) {
return describeItem(name, level, false);
}
static String describeItem(String name, int level, boolean rush) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("name is blank");
}
if (level < 1) {
throw new IllegalArgumentException("level: " + level);
}
return name + ":" + level + ":" + rush;
}Verify that all overloads follow the same validation. Then consider whether rush should be changed to an enum.
Fault Experiment
Turn on each one individually and record the first diagnostic:
// static int convert(int value) { return value; }
// static long convert(int number) { return number; } // Change only the return type// static void print(String value) { }
// static void print(Integer value) { }
// print(null); // Ambiguity// static int missingReturn(boolean flag) {
// if (flag) return 1;
// }Distinguish between duplicate signatures, overload ambiguity, and the normal path lacking a return value.
Safe Cleanup
pwd
test ! -e out || rm -r -- outConfirm that the files are located in this experiment directory and delete only the artifacts produced in this chapter.
Acceptance and Cleanup
Add zero and negative-input cases for the pure methods, retaining the Integer.MIN_VALUE case, and that array experiments can be explained using "reference value copies." Be able to describe the selection phase for each of the four overloads. Stack traces must be traced back from the point where an exception is exposed to main. Three types of faults should be marked separately as duplicate signatures, call ambiguity, and missing return paths. After saving the records, clean up the temporary directory:
cd
ls -ld -- "$chapter5_lab_root"
rm -r -- "$chapter5_lab_root"Paths for methods and recursion have already been verified. The next chapter will place a group of values of the same type into a contiguous index space.