Operators, Expressions, and Working with Strings
Arithmetic, comparison, and logical operators, and the String methods you'll reach for constantly — plus the immutability trap that catches every beginner once.
What you'll learn
- Use arithmetic, comparison, and logical operators to build correct expressions
- Explain integer division and operator precedence pitfalls
- Use core String methods to inspect, transform, and combine text without mutating the original
Prerequisites
Explanation
Java's arithmetic, comparison, and logical operators look familiar from most C-family languages, with one sharp edge worth learning early: integer division truncates. 7 / 2 evaluates to 3, not 3.5 — because both operands are int, Java performs integer division and discards the remainder entirely (use 7 % 2 to get that remainder, 1). The fix, when you want a real fractional result, is to make at least one operand a floating-point type: 7 / 2.0 evaluates to 3.5. This single rule causes more silent, wrong-answer bugs in beginner Java code than almost anything else, precisely because it never throws an error — it just quietly gives you the wrong number.
Comparison operators (==, !=, <, >, <=, >=) work as expected on primitives, but as the previous lesson noted, == on reference types (including String) compares identity, not content — new String("cat") == new String("cat") is false, even though the text is identical, because they're two distinct objects. Comparing String content correctly requires .equals(): "cat".equals(otherString). Logical operators && and || short-circuit: in a() && b(), if a() returns false, b() is never called at all — a behavior you can rely on to safely guard against errors, e.g. list != null && list.size() > 0 never calls .size() on a null reference, because && stops evaluating the moment the left side is false.
Strings, being immutable, expose a rich set of methods that all return a new String rather than modifying the original: .length(), .substring(start, end), .indexOf(text), .toUpperCase()/.toLowerCase(), .trim()/.strip(), .replace(old, new), .split(delimiter), and .equals()/.equalsIgnoreCase() for content comparison. For building a String piece by piece — especially inside a loop — use StringBuilder instead of repeated + concatenation: each + on Strings silently creates a brand-new String object, so concatenating in a loop with + is quadratic in the number of iterations, while StringBuilder.append() grows an internal, mutable buffer in place.
Example
Integer-division truncation, modeled with Math.trunc since JS division is always floating-point.
function javaIntDivide(a, b) {
return Math.trunc(a / b); // Java's int/int truncates toward zero, just like this
}
console.log(javaIntDivide(7, 2)); // 3, not 3.5
console.log(7 / 2); // 3.5 -- what you'd get if either operand were a double
console.log(7 % 2); // 1 -- the remainder int division throws awayTry it yourself
Predict javaIntDivide(-7, 2) before running -- Java's truncation rounds toward zero, not toward negative infinity.
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Guided exercise
Guided exercise
Write intDivide(a, b) and remainder(a, b) that model Java's int / and % operators exactly: division truncates toward zero (use Math.trunc), and the remainder has the same sign as the dividend a.
Checks: 7 / 2 == 3 · -7 / 2 == -3 (truncation toward zero) · 7 % 2 == 1 · -7 % 2 == -1
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Independent exercise
Independent exercise
Write contentEquals(s1, s2) modeling Java's String.equals(): true only if both are non-null and have identical characters -- never based on object identity. Then write safeLength(s) modeling short-circuit evaluation: returns s.length if s is not null/undefined, otherwise 0, without throwing.
Checks: equal strings compare equal by content · different strings compare unequal · null never equals a real string · safeLength returns the real length for a real string · safeLength returns 0 for null without throwing
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Common mistakes
- Writing `int average = (a + b) / 2;` when a fractional average was intended -- integer division silently truncates instead of erroring.
- Comparing Strings with == instead of .equals() -- it often 'accidentally works' for literal strings due to an implementation detail called string interning, then mysteriously breaks for strings built at runtime (e.g. via concatenation).
- Concatenating Strings with + inside a loop that runs many times -- each + allocates a new String, making the loop far slower than using StringBuilder.
Knowledge check
Takeaway
Integer division truncates and content equality needs .equals(), not ==, on Strings and every other reference type — both are silent, not error-throwing, so they only surface as wrong answers if you don't already know the rule.
Summary
Arithmetic on two ints stays an int and truncates; use a floating-point operand for a fractional result. == compares identity on reference types; .equals() compares content. && and || short-circuit, which is the idiomatic way to guard against null before calling a method.
References
Your notes
Notes save automatically.
Finished this lesson?
Mark it complete to track your progress and schedule a future review.
AI tutor
The optional AI tutor isn't enabled in this deployment. All lessons, exercises, quizzes, and search work fully without it.