1Z0-830 Data Types - Java SE 21 Certification Prep
Primitive Data Types
Java has 8 primitive data types that represent the most basic values. Unlike objects, primitives are stored directly in memory and are not instances of classes. Understanding their characteristics, ranges, and default values is fundamental for the 1Z0-830 exam.
Primitive Types Summary:
- byte - 8 bits, range: -128 to 127, default: 0
- short - 16 bits, range: -32,768 to 32,767, default: 0
- int - 32 bits, range: -2,147,483,648 to 2,147,483,647, default: 0
- long - 64 bits, range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, default: 0L
- float - 32 bits, IEEE 754 floating point, default: 0.0f
- double - 64 bits, IEEE 754 floating point, default: 0.0d
- char - 16 bits, Unicode character, range: 0 to 65,535, default: '\u0000'
- boolean - true or false, default: false
// Integer type declarations and ranges
byte b = 127; // Maximum byte value
byte b2 = -128; // Minimum byte value
// byte b3 = 128; // Compile error - out of range
short s = 32767; // Maximum short value
short s2 = -32768; // Minimum short value
int i = 2147483647; // Maximum int value (Integer.MAX_VALUE)
int i2 = -2147483648; // Minimum int value (Integer.MIN_VALUE)
long l = 9223372036854775807L; // Maximum long value - note L suffix
long l2 = -9223372036854775808L; // Minimum long value
// Long literals require L suffix for values outside int range
long large = 3000000000L; // L suffix required (exceeds int range)
long small = 100; // L suffix optional (within int range)
// Floating-point declarations
float f = 3.14f; // f or F suffix required for float literals
float f2 = 3.14F; // Capital F also valid
// float f3 = 3.14; // Compile error - double literal needs cast or suffix
double d = 3.14; // Default for decimal literals (no suffix needed)
double d2 = 3.14d; // d or D suffix optional
double d3 = 3.14D;
// Scientific notation
double scientific = 1.5e10; // 1.5 x 10^10 = 15000000000.0
double small = 1.5e-5; // 1.5 x 10^-5 = 0.000015
float scientificF = 3.2e5f; // 3.2 x 10^5 = 320000.0
// Integer literal formats
int decimal = 42; // Decimal (base 10)
int binary = 0b101010; // Binary (base 2) - prefix 0b or 0B
int binary2 = 0B101010; // Capital B also valid
int octal = 052; // Octal (base 8) - prefix 0
int hex = 0x2A; // Hexadecimal (base 16) - prefix 0x or 0X
int hex2 = 0X2A; // Capital X also valid
int hexLower = 0x2a; // Hex digits can be lowercase
// All represent the value 42
System.out.println(decimal); // 42
System.out.println(binary); // 42
System.out.println(octal); // 42
System.out.println(hex); // 42
// Underscores in numeric literals (Java 7+)
// Improves readability for large numbers
long creditCard = 1234_5678_9012_3456L;
int million = 1_000_000;
int binary = 0b1010_1010_1010_1010;
int hex = 0x1234_ABCD;
double pi = 3.14_15_92;
// Underscores rules - can appear between digits only
int valid1 = 1_000; // OK
int valid2 = 1__000; // OK - multiple underscores
int valid3 = 0x1_2_3; // OK
// int invalid1 = _1000; // Error - cannot start with underscore
// int invalid2 = 1000_; // Error - cannot end with underscore
// double invalid3 = 1._5; // Error - adjacent to decimal point
// double invalid4 = 1_.5; // Error - adjacent to decimal point
// long invalid5 = 1000_L; // Error - adjacent to suffix
// Character literals
char letter = 'A'; // Single character in single quotes
char digit = '9'; // Characters include digits
char symbol = '$';
// Unicode escape sequences - \uXXXX format
char unicode = '\u0041'; // Unicode for 'A'
char euro = '\u20AC'; // Euro symbol
char smiley = '\u263A'; // Smiley face
// Escape sequences
char newline = '\n'; // Newline
char tab = '\t'; // Tab
char backslash = '\\'; // Backslash
char singleQuote = '\''; // Single quote
char doubleQuote = '\"'; // Double quote
char carriageReturn = '\r'; // Carriage return
char backspace = '\b'; // Backspace
char formFeed = '\f'; // Form feed
// Octal escape sequences - \DDD format (not commonly used)
char octalChar = '\101'; // Octal 101 = 'A'
// char is an unsigned 16-bit integer
char minChar = '\u0000'; // Minimum: 0
char maxChar = '\uffff'; // Maximum: 65535
// Can perform arithmetic with char (promotes to int)
char c = 'A';
System.out.println(c + 1); // 66 (int result, not char)
char next = (char)(c + 1); // 'B' (needs cast back to char)
// Boolean type
boolean isTrue = true;
boolean isFalse = false;
// boolean wrong = 1; // Compile error - cannot use 0/1 for boolean
// boolean wrong2 = "true"; // Compile error - must be literal true/false
// Boolean cannot be cast or converted to/from other types
// if (1) {} // Compile error in Java (works in C/C++)
if (isTrue) {} // Correct
// Default values (for instance and class variables, not local variables)
// byte, short, int, long: 0
// float, double: 0.0
// char: '\u0000' (null character, displays as empty)
// boolean: false
// Object references: null
class Defaults {
byte b; // 0
short s; // 0
int i; // 0
long l; // 0L
float f; // 0.0f
double d; // 0.0d
char c; // '\u0000'
boolean bool; // false
String str; // null
}
// Local variables have NO default value - must be initialized
void method() {
int x;
// System.out.println(x); // Compile error - x not initialized
x = 5;
System.out.println(x); // OK now
}
// Overflow behavior
byte max = 127;
max++; // Overflows to -128 (wraps around)
System.out.println(max); // -128
int maxInt = Integer.MAX_VALUE;
maxInt++; // Overflows to Integer.MIN_VALUE
System.out.println(maxInt); // -2147483648
// Floating-point special values
double positiveInfinity = 1.0 / 0.0; // Infinity
double negativeInfinity = -1.0 / 0.0; // -Infinity
double notANumber = 0.0 / 0.0; // NaN (Not a Number)
System.out.println(Double.isInfinite(positiveInfinity)); // true
System.out.println(Double.isNaN(notANumber)); // true
// NaN comparison behavior
System.out.println(notANumber == notANumber); // false - NaN != NaN!
System.out.println(notANumber != notANumber); // true
Exam Tip: Underscores in numeric literals can only appear between digits, not at the start, end, or adjacent to decimal points or type suffixes.
_1000, 1000_, 1._5, and 1000_L are all invalid. Remember that char is an unsigned 16-bit integer that can hold Unicode characters from 0 to 65535. Floating-point division by zero produces Infinity (not an exception), and 0.0/0.0 produces NaN.
Wrapper Classes
Each primitive type has a corresponding wrapper class that allows primitives to be treated as objects. This is essential for using primitives with collections, generics, and other object-oriented features.
// Wrapper classes for each primitive
// byte -> Byte
// short -> Short
// int -> Integer
// long -> Long
// float -> Float
// double -> Double
// char -> Character
// boolean -> Boolean
// Autoboxing - automatic primitive to wrapper conversion
Integer wrapped = 42; // int -> Integer (autoboxing)
Double d = 3.14; // double -> Double
Boolean b = true; // boolean -> Boolean
Character c = 'A'; // char -> Character
// Unboxing - automatic wrapper to primitive conversion
int primitive = wrapped; // Integer -> int (unboxing)
double primitiveD = d; // Double -> double
// Explicit boxing (old style, rarely needed now)
Integer explicitBox = Integer.valueOf(42);
Double explicitBoxD = Double.valueOf(3.14);
// Unboxing with null causes NullPointerException
Integer nullInt = null;
// int x = nullInt; // NullPointerException at runtime!
// Parsing strings to primitives
int parsed = Integer.parseInt("42");
long parsedLong = Long.parseLong("1000");
double parsedDouble = Double.parseDouble("3.14");
boolean parsedBool = Boolean.parseBoolean("true");
// Parsing with radix (base)
int binary = Integer.parseInt("1010", 2); // Binary: 10
int hex = Integer.parseInt("2A", 16); // Hexadecimal: 42
int octal = Integer.parseInt("52", 8); // Octal: 42
// Parsing errors throw NumberFormatException
try {
int invalid = Integer.parseInt("abc"); // NumberFormatException
} catch (NumberFormatException e) {
System.out.println("Invalid number format");
}
// valueOf() methods - parse and return wrapper object
Integer wrappedParsed = Integer.valueOf("42");
Double wrappedDouble = Double.valueOf("3.14");
// Converting primitives/wrappers to String
String s1 = Integer.toString(42); // "42"
String s2 = String.valueOf(42); // "42"
String s3 = 42 + ""; // "42" (concatenation)
String binary = Integer.toBinaryString(42); // "101010"
String hex = Integer.toHexString(42); // "2a"
String octal = Integer.toOctalString(42); // "52"
// Wrapper class constants
int maxInt = Integer.MAX_VALUE; // 2147483647
int minInt = Integer.MIN_VALUE; // -2147483648
int intBytes = Integer.BYTES; // 4 (number of bytes)
int intSize = Integer.SIZE; // 32 (number of bits)
long maxLong = Long.MAX_VALUE;
double maxDouble = Double.MAX_VALUE;
double minDouble = Double.MIN_VALUE; // Smallest positive value, not most negative!
double minNormal = Double.MIN_NORMAL; // Smallest normal positive value
// Comparing wrappers - == vs equals()
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true (cached!)
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false (not cached, different objects)
System.out.println(c.equals(d)); // true (compares values)
// Integer caching: -128 to 127 are cached
// Values in this range use the same object from cache
// Values outside create new objects
Integer cached1 = Integer.valueOf(100); // From cache
Integer cached2 = Integer.valueOf(100); // Same object from cache
System.out.println(cached1 == cached2); // true
Integer notCached1 = Integer.valueOf(200); // New object
Integer notCached2 = Integer.valueOf(200); // New object
System.out.println(notCached1 == notCached2); // false
// new Integer() always creates new object (deprecated in Java 9+)
Integer newObj1 = new Integer(100); // Deprecated - don't use
Integer newObj2 = new Integer(100);
System.out.println(newObj1 == newObj2); // false (different objects)
// Always use equals() to compare wrapper objects
Integer x = 150;
Integer y = 150;
System.out.println(x.equals(y)); // Correct way - true
// Comparison methods
Integer num1 = 42;
Integer num2 = 100;
int comparison = num1.compareTo(num2); // Negative (42 < 100)
int comparison2 = Integer.compare(42, 100); // Static method, same result
// Wrapper class utility methods
System.out.println(Integer.max(10, 20)); // 20
System.out.println(Integer.min(10, 20)); // 10
System.out.println(Integer.sum(10, 20)); // 30
System.out.println(Math.abs(-42)); // 42
// Character wrapper has special utility methods
System.out.println(Character.isDigit('5')); // true
System.out.println(Character.isLetter('A')); // true
System.out.println(Character.isLetterOrDigit('5')); // true
System.out.println(Character.isUpperCase('A')); // true
System.out.println(Character.isLowerCase('a')); // true
System.out.println(Character.isWhitespace(' ')); // true
System.out.println(Character.toUpperCase('a')); // 'A'
System.out.println(Character.toLowerCase('A')); // 'a'
// Boolean wrapper
Boolean bool1 = Boolean.valueOf("true"); // true
Boolean bool2 = Boolean.valueOf("TRUE"); // true (case-insensitive)
Boolean bool3 = Boolean.valueOf("yes"); // false (only "true" returns true)
// Autoboxing in expressions
Integer result = 5 + 10; // int 15 autoboxed to Integer
Integer sum = new Integer(5) + new Integer(10); // Unbox, add, autobox
// Mixing primitives and wrappers
int primitive = 5;
Integer wrapper = 10;
int total = primitive + wrapper; // Wrapper unboxed to int
Integer total2 = primitive + wrapper; // Result autoboxed to Integer
// Wrapper immutability - wrappers are immutable like String
Integer num = 100;
Integer original = num;
num = num + 1; // Creates new Integer object
System.out.println(original); // Still 100
System.out.println(num); // 101 (different object)
Exam Tip: Integer caching is critical for the exam - values from -128 to 127 are cached and reused. Using == on cached values returns true, but values outside this range create new objects, making == return false even with equal values. Always use equals() to compare wrapper objects. Unboxing a null wrapper causes NullPointerException. Remember that Double.MIN_VALUE is the smallest positive value, not the most negative value (unlike Integer.MIN_VALUE).
String Class
Strings are immutable sequences of characters in Java. Every modification creates a new String object. Understanding String behavior, the String pool, and common methods is essential for the exam.
// String creation methods
String s1 = "Hello"; // String literal - stored in String pool
String s2 = new String("Hello"); // New object on heap, not in pool
String s3 = new String(new char[]{'H','i'}); // From char array
// String pool (interning)
// String literals are automatically interned in a special memory area
String a = "Hello";
String b = "Hello";
System.out.println(a == b); // true - same reference from pool
String c = new String("Hello");
System.out.println(a == c); // false - c is new heap object
System.out.println(a.equals(c)); // true - same content
// Explicit interning
String d = new String("Hello").intern(); // Returns reference from pool
System.out.println(a == d); // true - both reference pool object
// String concatenation creates new String objects
String original = "Hello";
String modified = original + " World"; // New String object created
System.out.println(original); // "Hello" - unchanged (immutable)
System.out.println(modified); // "Hello World"
// Concatenation at compile time vs runtime
String compile = "Hello" + " " + "World"; // Compiled to single "Hello World" literal
String runtime = "Hello";
runtime = runtime + " " + "World"; // Creates intermediate String objects
// Length and character access
String str = "Hello World";
int length = str.length(); // 11 (number of characters)
char firstChar = str.charAt(0); // 'H' (zero-indexed)
char lastChar = str.charAt(str.length() - 1); // 'd'
// char invalid = str.charAt(11); // StringIndexOutOfBoundsException
// Searching within strings
String text = "Hello World Hello";
int firstIndex = text.indexOf("o"); // 4 (first occurrence)
int lastIndex = text.lastIndexOf("o"); // 17 (last occurrence)
int notFound = text.indexOf("xyz"); // -1 (not found)
// indexOf with starting position
int secondO = text.indexOf("o", 5); // 7 (starts search from index 5)
// indexOf with substring
int helloPos = text.indexOf("Hello"); // 0
int secondHello = text.indexOf("Hello", 1); // 12
// Extracting substrings
String substring1 = str.substring(0, 5); // "Hello" (from 0 inclusive to 5 exclusive)
String substring2 = str.substring(6); // "World" (from 6 to end)
String copy = str.substring(0); // "Hello World" (entire string)
// Empty substring at boundaries
String empty = str.substring(5, 5); // "" (empty string, not error)
// Case conversion
String lower = str.toLowerCase(); // "hello world"
String upper = str.toUpperCase(); // "HELLO WORLD"
System.out.println(str); // "Hello World" - original unchanged
// Trimming whitespace
String spaces = " Hello World ";
String trimmed = spaces.trim(); // "Hello World" (removes leading/trailing)
System.out.println(spaces); // " Hello World " - original unchanged
// strip() - Unicode-aware whitespace removal (Java 11+)
String unicodeSpaces = "\u2000Hello\u2000";
String stripped = unicodeSpaces.strip(); // "Hello" (removes Unicode whitespace)
String stripLeading = unicodeSpaces.stripLeading(); // "Hello\u2000"
String stripTrailing = unicodeSpaces.stripTrailing(); // "\u2000Hello"
// Replacing characters and substrings
String replaced = str.replace("l", "L"); // "HeLLo WorLd" (all occurrences)
String replacedFirst = str.replaceFirst("l", "L"); // "HeLlo World" (first only)
String replacedAll = str.replaceAll("l+", "L"); // "HeLo WorLd" (regex: one or more 'l')
// Checking string properties
boolean starts = str.startsWith("Hello"); // true
boolean ends = str.endsWith("World"); // true
boolean contains = str.contains("llo"); // true
boolean empty = str.isEmpty(); // false (checks length == 0)
boolean blank = " ".isBlank(); // true (Java 11+ - all whitespace)
// String equality
String str1 = "hello";
String str2 = "HELLO";
System.out.println(str1.equals(str2)); // false (case-sensitive)
System.out.println(str1.equalsIgnoreCase(str2)); // true (case-insensitive)
// Comparing strings lexicographically
int cmp1 = "apple".compareTo("banana"); // Negative (apple < banana)
int cmp2 = "banana".compareTo("apple"); // Positive (banana > apple)
int cmp3 = "apple".compareTo("apple"); // 0 (equal)
int cmp4 = "Apple".compareToIgnoreCase("apple"); // 0 (case-insensitive)
// Splitting strings
String csv = "apple,banana,cherry";
String[] fruits = csv.split(","); // ["apple", "banana", "cherry"]
String multiSpace = "a b c";
String[] parts = multiSpace.split(" +"); // ["a", "b", "c"] (regex: one or more spaces)
// Split with limit
String data = "a:b:c:d";
String[] limited = data.split(":", 2); // ["a", "b:c:d"] (limit splits to 2 parts)
// Joining strings
String joined = String.join("-", "a", "b", "c"); // "a-b-c"
String[] words = {"Hello", "World"};
String sentence = String.join(" ", words); // "Hello World"
// Repeating strings (Java 11+)
String repeated = "ab".repeat(3); // "ababab"
String noRepeat = "hello".repeat(0); // "" (empty string)
// String invalid = "x".repeat(-1); // IllegalArgumentException
// Converting to/from char array
char[] chars = str.toCharArray(); // ['H','e','l','l','o',' ','W','o','r','l','d']
String fromChars = new String(chars); // "Hello World"
String fromCharRange = new String(chars, 0, 5); // "Hello"
// Getting characters as code points (for Unicode)
int codePoint = str.codePointAt(0); // Code point of 'H'
int count = str.codePointCount(0, str.length()); // Number of Unicode code points
// String formatting
String formatted = String.format("Name: %s, Age: %d", "Alice", 30);
// "Name: Alice, Age: 30"
// formatted() method (Java 15+)
String formatted2 = "Name: %s, Age: %d".formatted("Bob", 25);
// Checking for specific content
boolean hasNumber = "abc123".matches(".*\\d.*"); // true (contains digit)
boolean onlyLetters = "abc".matches("[a-zA-Z]+"); // true (only letters)
// String immutability implications
String s = "Hello";
s.concat(" World"); // Creates new String but doesn't assign
System.out.println(s); // "Hello" - unchanged!
s = s.concat(" World"); // Must reassign to see change
System.out.println(s); // "Hello World"
// Multiple modifications create multiple objects (inefficient)
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // Creates 1000 intermediate String objects!
}
// Performance: intern() caution
// Don't intern strings in loops - can fill up String pool memory
for (int i = 0; i < 1000000; i++) {
String s = new String("test" + i).intern(); // BAD - fills String pool
}
// String literals in switch statements (Java 7+)
String command = "start";
switch (command) {
case "start":
System.out.println("Starting...");
break;
case "stop":
System.out.println("Stopping...");
break;
}
Exam Tip: Strings are immutable - all modification methods return a new String. The original is never changed. String literals are stored in the String pool and reused (using == returns true for equal literals). new String() creates a new object on the heap, not in the pool. Always use equals() for content comparison, not ==. Methods like concat(), replace(), substring() return new String objects and must be assigned to see the result. The isBlank() method (Java 11+) returns true for empty or whitespace-only strings, while isEmpty() only checks for zero length.
StringBuilder and StringBuffer
StringBuilder (and StringBuffer) are mutable sequences of characters. Use them when performing many string modifications to avoid creating multiple intermediate String objects.
// Creating StringBuilder
StringBuilder sb = new StringBuilder(); // Empty, capacity 16
StringBuilder sb2 = new StringBuilder("Hello"); // With initial content
StringBuilder sb3 = new StringBuilder(100); // With initial capacity
// StringBuilder is mutable - changes the same object
StringBuilder builder = new StringBuilder("Hello");
builder.append(" World");
System.out.println(builder); // "Hello World"
// No assignment needed - object is modified in place
// Method chaining - all modification methods return 'this'
StringBuilder result = new StringBuilder()
.append("Hello")
.append(" ")
.append("World")
.append("!");
System.out.println(result); // "Hello World!"
// Common StringBuilder methods
// append() - adds to end
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // "Hello World"
sb.append(123); // "Hello World123"
sb.append(true); // "Hello World123true"
sb.append('!'); // "Hello World123true!"
// insert() - inserts at specified position
sb = new StringBuilder("Hello World");
sb.insert(5, ","); // "Hello, World"
sb.insert(0, ">> "); // ">> Hello, World"
sb.insert(sb.length(), " <<"); // ">> Hello, World <<"
// delete() - removes characters in range [start, end)
sb = new StringBuilder("Hello World");
sb.delete(5, 11); // "Hello" (removed " World")
sb.delete(0, 2); // "llo" (removed "He")
// deleteCharAt() - removes single character
sb = new StringBuilder("Hello");
sb.deleteCharAt(1); // "Hllo" (removed 'e')
// replace() - replaces range with new string
sb = new StringBuilder("Hello World");
sb.replace(6, 11, "Java"); // "Hello Java"
sb.replace(0, 5, "Hi"); // "Hi Java"
// reverse() - reverses the sequence
sb = new StringBuilder("Hello");
sb.reverse(); // "olleH"
// setCharAt() - replaces single character
sb = new StringBuilder("Hello");
sb.setCharAt(0, 'J'); // "Jello"
// setLength() - changes length
sb = new StringBuilder("Hello World");
sb.setLength(5); // "Hello" (truncates)
sb.setLength(10); // "Hello\0\0\0\0\0" (extends with null chars)
// Capacity management
sb = new StringBuilder(); // Initial capacity 16
int capacity = sb.capacity(); // 16
sb.append("This is a longer string");
int newCapacity = sb.capacity(); // Automatically increased (34)
sb.ensureCapacity(100); // Ensures minimum capacity
sb.trimToSize(); // Reduces capacity to match length
// Getting information
int length = sb.length(); // Current length
char ch = sb.charAt(0); // Character at index
String sub = sb.substring(0, 5); // Substring (returns String, not StringBuilder)
// Converting to String
String result = sb.toString(); // Creates new String object
// StringBuilder vs String performance
// String - creates many intermediate objects
String s = "";
for (int i = 0; i < 1000; i++) {
s = s + i; // Creates 1000+ String objects
}
// StringBuilder - modifies single object
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i); // Modifies same StringBuilder object
}
String result = sb.toString(); // Single String created at end
// StringBuilder vs StringBuffer
// StringBuilder: NOT thread-safe, faster (use in single-threaded code)
// StringBuffer: Thread-safe (synchronized), slower
// StringBuffer usage (same API as StringBuilder)
StringBuffer buffer = new StringBuffer();
buffer.append("Thread-safe");
buffer.append(" operations");
// In practice, almost always use StringBuilder
// Only use StringBuffer if multiple threads access same buffer
// Common mistakes
// Mistake 1: Not assigning substring result
sb = new StringBuilder("Hello World");
sb.substring(0, 5); // Returns String "Hello" but doesn't modify sb
System.out.println(sb); // Still "Hello World"!
// Correct:
String result = sb.substring(0, 5); // Capture returned String
// Or to modify sb:
sb.delete(5, sb.length()); // Actually removes characters
// Mistake 2: Trying to use + with StringBuilder
StringBuilder sb1 = new StringBuilder("Hello");
StringBuilder sb2 = new StringBuilder("World");
// StringBuilder result = sb1 + sb2; // Compile error!
// Correct:
sb1.append(sb2); // Or: sb1.append(sb2.toString());
// Comparing StringBuilder objects
StringBuilder a = new StringBuilder("Hello");
StringBuilder b = new StringBuilder("Hello");
System.out.println(a == b); // false (different objects)
System.out.println(a.equals(b)); // false (equals() not overridden!)
System.out.println(a.toString().equals(b.toString())); // true (compare as Strings)
// StringBuilder doesn't override equals() or hashCode()
// Cannot use StringBuilder as HashMap key effectively
// Efficient StringBuilder usage patterns
// Estimate capacity if you know approximate final size
int estimatedSize = 1000;
StringBuilder efficient = new StringBuilder(estimatedSize);
for (int i = 0; i < 100; i++) {
efficient.append("some text");
}
// Reusing StringBuilder
StringBuilder reusable = new StringBuilder();
for (int i = 0; i < 10; i++) {
reusable.setLength(0); // Clear contents
reusable.append("Iteration ").append(i);
System.out.println(reusable);
}
// StringBuilder in method signatures
// Return String, not StringBuilder (StringBuilder is implementation detail)
public String buildMessage(String name) {
StringBuilder sb = new StringBuilder();
sb.append("Hello, ").append(name).append("!");
return sb.toString(); // Return String
}
Exam Tip: StringBuilder is mutable - methods like append(), insert(), delete() modify the same object and return 'this' for chaining. Use StringBuilder instead of String concatenation in loops for better performance. substring() returns a String (not StringBuilder) and doesn't modify the original. StringBuilder doesn't override equals() - to compare contents, convert to String first. StringBuilder is not thread-safe; StringBuffer is the synchronized (thread-safe) version. Remember that setLength() can truncate or extend the sequence.
Local Variable Type Inference (var)
The var keyword (introduced in Java 10) allows the compiler to infer the type of local variables from their initializer expressions. This reduces verbosity while maintaining type safety.// Basic var usage - compiler infers type from right side var message = "Hello"; // Inferred as String var number = 42; // Inferred as int var decimal = 3.14; // Inferred as double var flag = true; // Inferred as boolean // With object creation var list = new ArrayList(); // Inferred as ArrayList var map = new HashMap (); // Inferred as HashMap var file = new File("data.txt"); // Inferred as File // Type is determined at compile time, not runtime var obj = "Hello"; // obj = 42; // Compile error - obj is String, not Object // var with generics var names = new ArrayList (); // ArrayList names.add("Alice"); // names.add(123); // Compile error - expects String var numbers = List.of(1, 2, 3); // List (immutable) var mutableList = new ArrayList<>(numbers); // ArrayList // var with diamond operator var list2 = new ArrayList<>(); // ArrayList
Exam Tip: var is NOT a keyword but a reserved type name - you can use "var" as a variable name. var can only be used with local variables that have an initializer. It cannot be used for method parameters, return types, fields, or variables without initializers. var cannot be initialized with null without an explicit cast. The type is inferred at compile time and is fixed - you cannot reassign to a different type. var is not allowed with array initializers like {1,2,3} but works with new int[]{1,2,3}. When using var with diamond operator (<>), be careful as the type might be inferred as Object if not specified.
Text Blocks (Java 15+)
Text blocks provide a cleaner way to write multi-line string literals without excessive escape sequences and concatenation. They preserve formatting and improve code readability.
// Traditional multi-line string (messy with escape sequences)
String json = "{\n" +
" \"name\": \"Alice\",\n" +
" \"age\": 30\n" +
"}";
// Text block - much cleaner
String jsonBlock = """
{
"name": "Alice",
"age": 30
}
""";
// Text block syntax rules
// 1. Opening delimiter (""") must be followed by line terminator
// String invalid = """Hello"""; // Compile error - no newline after """
String valid = """
Hello
""";
// 2. Content starts on line after opening delimiter
String text = """
Line 1
Line 2
""";
// Produces: "Line 1\nLine 2\n"
// 3. Closing delimiter position determines indentation
String leftAligned = """
Line 1
Line 2
"""; // No indentation preserved
String indented = """
Line 1
Line 2
"""; // 4 spaces of indentation preserved
// Closing delimiter determines baseline for incidental whitespace removal
String example1 = """
Hello
World
"""; // "Hello\nWorld\n" - indentation removed
String example2 = """
Hello
World
"""; // " Hello\n World\n" - less indentation, more preserved
// Intentional vs incidental whitespace
String poem = """
Roses are red,
Violets are blue,
Sugar is sweet,
And so are you.
""";
// Preserves relative indentation
// Escape sequences work in text blocks
String html = """
Title
Line 1\nLine 2
""";
// Special escape sequences for text blocks
// \ at end of line - prevents line break (line continuation)
String singleLine = """
Hello \
World\
""";
// Produces: "Hello World" (no line breaks)
String withBreak = """
Hello
World
""";
// Produces: "Hello\nWorld\n" (with line breaks)
// \s - explicit space (preserves trailing whitespace)
// Normally trailing spaces on a line are removed
String spaces = """
line1
line2
""";
// Trailing spaces removed: "line1\nline2\n"
String preservedSpaces = """
line1 \s
line2 \s
""";
// Trailing spaces preserved: "line1 \nline2 \n"
// \ - escape the newline
String noNewlines = """
First\
Second\
Third
""";
// Produces: "FirstSecondThird\n"
// Combining escapes
String formatted = """
Name: %s\
Age: %d
""".formatted("Alice", 30);
// Produces: "Name: AliceAge: 30\n"
// Mixed quotes in text blocks - no escaping needed
String quotes = """
He said, "Hello!"
She replied, 'Hi there!'
""";
// Triple quotes inside text block need escaping
String tripleQuotes = """
This is a text block with \"""triple quotes\""" inside
""";
// Empty lines and trailing newlines
String withEmptyLines = """
Line 1
Line 3
""";
// Produces: "Line 1\n\nLine 3\n"
// No trailing newline if closing delimiter on same line as content
String noTrailing = """
Line 1
Line 2""";
// Produces: "Line 1\nLine 2" (no trailing newline)
// String methods work on text blocks
String block = """
Hello
World
""";
int length = block.length(); // Includes newlines
String upper = block.toUpperCase();
String[] lines = block.split("\n"); // ["Hello", "World", ""]
// Formatted text blocks (Java 15+)
String formatted = """
Name: %s
Age: %d
""".formatted("Bob", 25);
// Using text blocks for SQL
String sql = """
SELECT id, name, email
FROM users
WHERE age > 18
AND status = 'active'
ORDER BY name
""";
// Using text blocks for JSON
String jsonData = """
{
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]
}
""";
// Using text blocks for HTML
String webpage = """
My Page
Welcome
""";
// Common mistakes with text blocks
// Mistake 1: Expecting different indentation behavior
String wrong = """
Indented
Less indented
""";
// Closing delimiter determines baseline
// Result: " Indented\nLess indented\n"
// Mistake 2: Not considering closing delimiter position
String unexpected = """
Line 1
Line 2
"""; // Closing delimiter all the way left
// Result: " Line 1\n Line 2\n" (preserves all indentation)
// Mistake 3: Forgetting text blocks are still String objects
String block = """
Hello
""";
String regular = "Hello\n";
System.out.println(block.equals(regular)); // true - same content
// Text blocks and String pool
String pooled1 = """
Hello
""";
String pooled2 = """
Hello
""";
System.out.println(pooled1 == pooled2); // true - interned
// Concatenation with text blocks
String combined = """
Part 1
""" + """
Part 2
""";
// Performance - text blocks are compiled to regular strings
// No runtime overhead compared to traditional strings
Exam Tip: Text blocks must have the opening triple quotes followed immediately by a line terminator - cannot start content on same line. The position of the closing delimiter determines how much indentation is removed from all lines. Use backslash (\) at end of line to prevent line break. Use \s to explicitly preserve trailing whitespace. Text blocks are still String objects and are interned in the String pool like regular string literals.
Type Casting and Conversion
Type casting converts a value from one type to another. Java supports both implicit (widening) and explicit (narrowing) conversions for primitive types and reference types.
// Primitive type casting
// Widening (implicit) conversions - smaller to larger type
// No data loss, happens automatically
// Order: byte -> short -> int -> long -> float -> double
// char -> int
byte b = 10;
short s = b; // byte -> short (automatic)
int i = s; // short -> int (automatic)
long l = i; // int -> long (automatic)
float f = l; // long -> float (automatic, may lose precision)
double d = f; // float -> double (automatic)
// char widens to int
char c = 'A'; // 65
int charAsInt = c; // 65 (automatic widening)
// Narrowing (explicit) conversions - larger to smaller type
// May lose data, requires explicit cast
double d = 3.99;
int i = (int) d; // 3 (truncates decimal, doesn't round!)
System.out.println(i); // 3, not 4
long big = 1000L;
int smaller = (int) big; // OK if value fits
byte smallest = (byte) big; // May overflow if value too large
// Truncation, not rounding
System.out.println((int) 3.1); // 3
System.out.println((int) 3.5); // 3
System.out.println((int) 3.9); // 3
System.out.println((int) -3.9); // -3
// To round, use Math.round()
double value = 3.7;
int rounded = (int) Math.round(value); // 4
long roundedLong = Math.round(value); // Returns long, not int
// Overflow in narrowing conversions
int large = 130;
byte b = (byte) large; // -126 (overflow, wraps around)
int max = Integer.MAX_VALUE;
byte b2 = (byte) max; // -1 (overflow)
// Casting between char and int
char letter = 'A';
int code = (int) letter; // 65 (explicit cast, but widening)
int code2 = letter; // 65 (automatic widening)
int num = 66;
char charB = (char) num; // 'B' (narrowing, needs explicit cast)
// boolean cannot be cast to/from any other type
boolean flag = true;
// int x = (int) flag; // Compile error
// boolean b = (boolean) 1; // Compile error
// Compound assignment performs implicit cast
byte b = 10;
b = b + 1; // Compile error - b + 1 is int
b = (byte)(b + 1); // OK - explicit cast
b += 1; // OK - compound operator includes implicit cast
short s = 5;
s = s * 2; // Compile error - s * 2 is int
s *= 2; // OK - implicit cast
// Promotion in expressions
byte b1 = 10;
byte b2 = 20;
// byte sum = b1 + b2; // Compile error - result is int
int sum = b1 + b2; // OK
byte sum2 = (byte)(b1 + b2); // OK with cast
// All integer types smaller than int are promoted to int in expressions
byte b = 1;
short s = 2;
char c = 'A';
int result = b + s + c; // All promoted to int
// long if any operand is long
int i = 10;
long l = 20L;
long result = i + l; // Result is long
// float if any operand is float (and no double)
int i = 10;
float f = 5.5f;
float result = i + f; // Result is float
// double if any operand is double
float f = 5.5f;
double d = 3.14;
double result = f + d; // Result is double
// Reference type casting
// Upcasting (implicit) - subclass to superclass
String str = "Hello";
Object obj = str; // String -> Object (automatic)
// Downcasting (explicit) - superclass to subclass
Object obj = "Hello";
String str = (String) obj; // OK - obj actually contains String
// ClassCastException at runtime if types incompatible
Object obj = Integer.valueOf(42);
// String str = (String) obj; // ClassCastException at runtime!
// Safe downcasting with instanceof
Object obj = "Hello";
if (obj instanceof String) {
String str = (String) obj; // Safe - checked first
System.out.println(str.length());
}
// Pattern matching with instanceof (Java 16+)
Object obj = "Hello";
if (obj instanceof String str) { // str is pattern variable
System.out.println(str.length()); // Can use str directly
}
// Pattern variable scope
if (obj instanceof String str) {
System.out.println(str); // str in scope
}
// System.out.println(str); // Compile error - str not in scope
// Negative instanceof
if (!(obj instanceof String str)) {
// str NOT in scope here
} else {
System.out.println(str); // str in scope in else block
}
// instanceof with null
Object obj = null;
boolean result = obj instanceof String; // false (null is not instance of anything)
// Casting with arrays
Object[] objArray = new String[5]; // OK - String[] is subtype of Object[]
// Integer[] intArray = (Integer[]) objArray; // ClassCastException at runtime
// Primitive arrays cannot be cast to Object arrays
int[] intArray = {1, 2, 3};
// Object[] objArray = intArray; // Compile error - incompatible types
// But can cast to Object (single object, not array of Objects)
Object obj = intArray; // OK - array is an object
// Casting and method overloading
class Example {
void process(int x) {
System.out.println("int: " + x);
}
void process(long x) {
System.out.println("long: " + x);
}
}
Example ex = new Example();
byte b = 5;
ex.process(b); // Calls process(int) - widening
ex.process((long) b); // Calls process(long) - explicit cast
// Loss of precision warning
long bigNum = 9876543210L;
float f = bigNum; // Allowed but may lose precision
System.out.println((long) f); // May not equal original value
// Integer division before casting
double result = 5 / 2; // 2.0 (integer division, then widened)
double correct = 5.0 / 2; // 2.5 (double division)
double correct2 = (double) 5 / 2; // 2.5 (cast before division)
double wrong = (double) (5 / 2); // 2.0 (division happens first)
Exam Tip: Casting from floating-point to integer truncates (doesn't round) - (int)3.9 equals 3. Narrowing conversions may cause overflow without warning. Compound operators (+=, *=, etc.) include an implicit cast. All integer types smaller than int are promoted to int in expressions. boolean cannot be cast to or from any other type. Always use instanceof to check before downcasting reference types. Pattern matching with instanceof (Java 16+) creates a pattern variable that's only in scope where the instanceof is true. Remember that null instanceof Type always returns false.
1Z0-830 Java SE 21 Certification - Table of Contents
Master all exam topics with comprehensive study guides and practice examples.
Popular Posts
1Z0-830 Java SE 21 Developer Certification
Azure AI Foundry Hello World
Azure AI Agent Hello World
Foundry vs Hub Projects
Build Agents with SDK
Bing Web Search Agent
Function Calling Agent
Spring Boot + Azure Key Vault Hello World Example
Spring Boot + Elasticsearch + Azure Key Vault Example
Spring Boot Azure AD (Entra ID) OAuth 2.0 Authentication
Deploy Spring Boot App to Azure App Service
Secure Azure App Service using Azure API Management
Deploy Spring Boot JAR to Azure App Service
Deploy Spring Boot + MySQL to Azure App Service
Spring Boot + Azure Managed Identity Example
Secure Spring Boot Azure Web App with Managed Identity + App Registration
Elasticsearch 8 Security - Integrate Azure AD OIDC