🃏 Math API and Wrapper Classes
Rule: Math class provides static methods for mathematical operations, while wrapper classes handle autoboxing/unboxing.
- Math methods: All static, work with primitives
- Autoboxing: Automatic conversion between primitives and wrapper objects
- Parsing: Wrapper classes convert strings to primitives
// Math class operations
double result1 = Math.pow(2, 3); // 8.0 (2^3)
double result2 = Math.sqrt(16); // 4.0
int result3 = Math.abs(-42); // 42
double result4 = Math.max(10.5, 20.3); // 20.3
double result5 = Math.min(10.5, 20.3); // 10.5
double result6 = Math.round(3.7); // 4.0
double result7 = Math.ceil(3.1); // 4.0 (round up)
double result8 = Math.floor(3.9); // 3.0 (round down)
// Random number generation
double random1 = Math.random(); // 0.0 <= x < 1.0
int random2 = (int)(Math.random() * 6) + 1; // Dice roll: 1-6
// Wrapper class autoboxing/unboxing
Integer wrapper = 42; // Autoboxing: int -> Integer
int primitive = wrapper; // Unboxing: Integer -> int
// Parsing strings to primitives
int parsed1 = Integer.parseInt("123"); // 123
double parsed2 = Double.parseDouble("45.6"); // 45.6
boolean parsed3 = Boolean.parseBoolean("true"); // true
// Wrapper class utility methods
String binary = Integer.toBinaryString(10); // "1010"
String hex = Integer.toHexString(255); // "ff"
Integer maxInt = Integer.MAX_VALUE; // 2147483647
Integer minInt = Integer.MIN_VALUE; // -2147483648
Autoboxing gotchas:
// Watch out for null pointer exceptions
Integer wrapper = null;
// int primitive = wrapper; // ❌ NullPointerException during unboxing
// Watch out for object equality vs value equality
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true (cached values -128 to 127)
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false (not cached, different objects)
System.out.println(c.equals(d)); // true (value comparison)
💡 Learning Tip: Remember “MATH = STATIC UTILITY” - Math methods are all static and work with primitives. Wrapper classes bridge primitives and objects.
Q: What’s the difference between Math.round()
, Math.ceil()
, and Math.floor()
?
A: round()
rounds to nearest integer, ceil()
always rounds up, floor()
always rounds down.
🃏 Arrays.binarySearch() and Arrays.compare()
Arrays.binarySearch() - Requires sorted array:
- Positive index if element found
- Negative value if not found:
-(insertion point) - 1
int[] sorted = {10, 20, 30, 40, 50};
// Element found:
int found = Arrays.binarySearch(sorted, 30); // Returns 2
System.out.println("Found at index: " + found);
// Element not found:
int notFound = Arrays.binarySearch(sorted, 25); // Returns -3
int insertionPoint = -notFound - 1; // -(-3) - 1 = 2
System.out.println("Would insert at index: " + insertionPoint);
Arrays.compare() vs Arrays.mismatch():
int[] a = {1, 2, 3, 4};
int[] b = {1, 2, 3, 4};
int[] c = {1, 2, 5, 4};
// Arrays.compare() - lexicographic comparison:
System.out.println(Arrays.compare(a, b)); // 0 (equal)
System.out.println(Arrays.compare(a, c)); // -2 (3 < 5, so negative)
// Arrays.mismatch() - find difference location:
System.out.println(Arrays.mismatch(a, b)); // -1 (no mismatch)
System.out.println(Arrays.mismatch(a, c)); // 2 (differ at index 2)
💡 Learning Tips:
- binarySearch: “Negative means missing” - use
-(result) - 1
for insertion point - compare() tells you “who wins”, mismatch() tells you “where they differ”
🃏 Array Operations and Utilities
Rule: Arrays class provides utility methods for common array operations like sorting, searching, and comparison.
import java.util.Arrays;
// Array creation and initialization
int[] numbers = {5, 2, 8, 1, 9};
String[] names = new String[3];
Arrays.fill(names, "Unknown"); // Fill entire array with value
// Sorting
Arrays.sort(numbers); // [1, 2, 5, 8, 9]
String[] words = {"zebra", "apple", "banana"};
Arrays.sort(words); // [apple, banana, zebra]
// Partial sorting
int[] partialSort = {5, 2, 8, 1, 9, 3, 7};
Arrays.sort(partialSort, 1, 4); // Sort indices 1-3: [5, 1, 2, 8, 9, 3, 7]
// Array copying
int[] original = {1, 2, 3, 4, 5};
int[] copy1 = Arrays.copyOf(original, 3); // [1, 2, 3]
int[] copy2 = Arrays.copyOf(original, 7); // [1, 2, 3, 4, 5, 0, 0]
int[] copy3 = Arrays.copyOfRange(original, 1, 4); // [2, 3, 4]
// Array equality
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
int[] arr3 = {1, 2, 4};
System.out.println(arr1 == arr2); // false (reference comparison)
System.out.println(Arrays.equals(arr1, arr2)); // true (content comparison)
System.out.println(Arrays.equals(arr1, arr3)); // false (different content)
// Multi-dimensional arrays
int[][] matrix1 = {{1, 2}, {3, 4}};
int[][] matrix2 = {{1, 2}, {3, 4}};
System.out.println(Arrays.equals(matrix1, matrix2)); // false (shallow comparison)
System.out.println(Arrays.deepEquals(matrix1, matrix2)); // true (deep comparison)
Array to String conversion:
int[] array = {1, 2, 3, 4, 5};
System.out.println(array); // [I@hashcode (not useful)
System.out.println(Arrays.toString(array)); // [1, 2, 3, 4, 5]
int[][] twoDArray = {{1, 2}, {3, 4}};
System.out.println(Arrays.toString(twoDArray)); // [references] (not useful)
System.out.println(Arrays.deepToString(twoDArray)); // [[1, 2], [3, 4]]
💡 Learning Tip: Remember “ARRAYS = UTILITY BELT” - Arrays class has tools for every common array operation. Use deepEquals() and deepToString() for multi-dimensional arrays.
Q: What’s the difference between Arrays.equals() and Arrays.deepEquals()?
A: equals() does shallow comparison (one level), while deepEquals() recursively compares multi-dimensional arrays.
🃏 Wrapper Class Comparison and Caching
Rule: Wrapper classes have reference equality quirks due to object caching for small values.
- Integer cache: -128 to 127 are cached (same object references)
- Boolean cache: TRUE and FALSE are cached
- Character cache: 0 to 127 are cached
// Integer caching behavior
Integer a1 = 127;
Integer b1 = 127;
System.out.println(a1 == b1); // true (cached, same object)
System.out.println(a1.equals(b1)); // true (value comparison)
Integer a2 = 128;
Integer b2 = 128;
System.out.println(a2 == b2); // false (not cached, different objects)
System.out.println(a2.equals(b2)); // true (value comparison)
// Forcing new objects
Integer a3 = new Integer(127); // Deprecated in Java 9+
Integer b3 = new Integer(127);
System.out.println(a3 == b3); // false (explicitly created new objects)
// valueOf vs constructor
Integer a4 = Integer.valueOf(127); // Uses cache if available
Integer b4 = Integer.valueOf(127);
System.out.println(a4 == b4); // true (cached)
// Boolean caching
Boolean bool1 = Boolean.valueOf(true);
Boolean bool2 = Boolean.valueOf(true);
System.out.println(bool1 == bool2); // true (cached)
Boolean bool3 = new Boolean(true); // Deprecated
Boolean bool4 = new Boolean(true);
System.out.println(bool3 == bool4); // false (new objects)
Safe comparison practices:
// Always use equals() for value comparison
Integer x = 200;
Integer y = 200;
// ❌ Unsafe - reference comparison
if (x == y) { /* may be false */ }
// ✅ Safe - value comparison
if (x.equals(y)) { /* always correct */ }
// ✅ Safe - null-safe comparison (Java 7+)
if (Objects.equals(x, y)) { /* handles nulls */ }
// ✅ Safe - unbox to primitives
if (x.intValue() == y.intValue()) { /* primitive comparison */ }
Parsing edge cases:
// NumberFormatException examples
try {
Integer.parseInt(""); // ❌ NumberFormatException
Integer.parseInt("12.5"); // ❌ NumberFormatException
Integer.parseInt("12L"); // ❌ NumberFormatException
Integer.parseInt("twelve"); // ❌ NumberFormatException
Integer.parseInt(null); // ❌ NumberFormatException
} catch (NumberFormatException e) {
System.out.println("Invalid number format");
}
// Valid parsing
int valid1 = Integer.parseInt("42"); // 42
int valid2 = Integer.parseInt("-123"); // -123
int valid3 = Integer.parseInt("+456"); // 456
// Radix parsing
int binary = Integer.parseInt("1010", 2); // 10 (binary)
int hex = Integer.parseInt("FF", 16); // 255 (hexadecimal)
int octal = Integer.parseInt("77", 8); // 63 (octal)
💡 Learning Tip: Remember “CACHE = CONFUSION” - small wrapper values may share references, so always use equals() for value comparison, not ==.
Q: Why does Integer a = 127; Integer b = 127; System.out.println(a == b)
print true, but the same code with 128 prints false?
A: Integer caches values from -128 to 127 for performance. Values in this range return the same object reference, while values outside create new objects.