Difficulty: Introductory to Intermediate
Prerequisites: Basic Java syntax, familiarity with primitive data types (int, double, boolean, char, String).
This topic is one of the most reliably tested areas on CS 312 exams at UT Austin. Expression evaluation questions require you to trace through operator precedence, type promotion, casting, and string concatenation rules, and to report the result with the correct data type. If you cannot reliably evaluate a multi-operator expression by hand, the code-tracing questions later in the exam become much harder.
Java evaluates expressions left to right, following operator precedence (multiplication and division before addition and subtraction, for instance). When an int meets a double in the same operation, the int is promoted to a double. The + operator concatenates when either side is a String, which changes everything that follows it in a left-to-right chain. Getting the data type of your answer right is just as important as getting the value right.
Operator precedence
The fixed order in which Java evaluates operators. Multiplicative operators (*, /, %) bind before additive (+, -). Unary operators (casts, negation) bind before both.
In simple terms: just like maths, multiplication and division happen before addition and subtraction, unless parentheses override.
Integer division (truncation)
When both operands of / are ints, Java discards the fractional part and returns an int. 7 / 2 produces 3, not 3.5.
Think of it as: Java chops the decimal off entirely rather than rounding.
Modulo (%)
Returns the remainder after integer division. 17 % 5 produces 2. Works on doubles too: 2.5 % 2.0 produces 0.5.
Think of it as: "what's left over after dividing?"
Type promotion (widening conversion)
When an arithmetic operator has one int operand and one double operand, Java automatically promotes the int to a double before performing the operation. The result is a double.
In simple terms: if a double shows up anywhere in an arithmetic expression, the result of that operation becomes a double.
Narrowing cast
An explicit (int) cast truncates a double to an int by discarding the decimal. The cast applies only to the value immediately to its right, not to the entire expression, unless parentheses group the expression.
Think of it as: the cast "grabs" only the next value, so (int) 2.7 * 10 casts 2.7 to 2 first, then multiplies.
String concatenation with +
When at least one operand of + is a String, Java converts the other operand to a String and concatenates. Evaluation proceeds left to right, so 2 + 3 + "x" produces "5x" (arithmetic first, then concatenation), while "x" + 2 + 3 produces "x23".
Think of it as: once a String appears, everything after it in a left-to-right chain gets glued on as text.
charAt(int index)
Returns the char at the specified zero-based index of a String. "CS312".charAt(2) returns '3'.
indexOf(String s)
Returns the index of the first occurrence of the given substring within the String, or -1 if not found. Case-sensitive.
== vs .equals() on Strings
== compares references (whether two variables point to the same object in memory). .equals() compares the actual character content. Two Strings can have the same characters but be different objects, so == returns false while .equals() returns true.
Think of it as: == asks "are these the same box?"; .equals() asks "do the boxes contain the same thing?"
Math.floor(double)
Returns the largest double value that is less than or equal to the argument and equal to a mathematical integer. For negatives, this rounds further from zero: Math.floor(-2.31) returns -3.0.
Math.round(double)
Returns the closest long to the argument. Rounds .5 cases toward positive infinity: Math.round(-1.5) returns -1 (not -2).
Parentheses first, then unary operators (casts, !, -), then *, /, %, then +, -.
Operators of the same precedence evaluate left to right.
Integer division truncates (chops the decimal): 10 / 3 yields 3.
Modulo gives the remainder: 73983 % 1000 yields 983.
If either operand is a double, the other is promoted to double and the result is double.
This applies per-operation, not to the whole expression at once. In 73983 % 1000 / 100 + 10 * 5 * 1.0, the % 1000, / 100, and 10 * 5 all happen in int land. Only when 50 meets * 1.0 does the result become 50.0, and then 9 + 50.0 becomes 59.0.
A char compared with == to an int compares the numeric Unicode value. 3 == '3' compares 3 to 51 (the Unicode value of '3'), so the result is false.
(int) casts only the immediately following value: (int) 2.752 * 10 + 5.0 casts 2.752 to 2, then evaluates 2 * 10 + 5.0 to get 25.0.
To cast the result of a larger expression, wrap it in parentheses: (int)(2.752 * 10 + 5.0) would give 32.
Left-to-right evaluation determines when concatenation kicks in.
A boolean can appear in a concatenation: (3 / 2 == 0) + "H" evaluates to false + "H", which is "falseH". From that point, everything concatenates.
Full example: (3 / 2 == 0) + "H" + 2 * 5 + 1.5 becomes false + "H" + 10 + 1.5, which is "falseH101.5".
Arithmetic to the LEFT of the first String operand is done as arithmetic. Arithmetic to the RIGHT is concatenated as text, unless grouped by parentheses.
charAt(index) returns a char (note the single quotes in the answer). Indexing is zero-based.
indexOf(String) returns an int. Returns -1 when the substring is not found. Case-sensitive: "super_tas".indexOf("TAs") returns -1 because "tas" is not "TAs".
toUpperCase() returns a new String object. It does not modify the original.
substring(beginIndex) returns a new String from beginIndex to the end.
== on objects (including Strings) checks reference identity.
"cat".toUpperCase() == "CAT" is false because toUpperCase() creates a new object.
d1.substring(4) creates a new String object, so == with the original is false.
String literals in the same class that are identical may share a reference via the String pool, but method results (substring, toUpperCase) always produce new objects.
|| (or) short-circuits: if the left side is true, the right side is not evaluated, but the result is true regardless.
&& (and) short-circuits: if the left side is false, the right side is not evaluated.
!= and == have lower precedence than arithmetic and relational operators.
Math.floor(-2.31) returns -3.0 (a double). Floor goes toward negative infinity.
Math.round(-1.5) returns -1 (a long). Java's Math.round rounds .5 toward positive infinity, so -1.5 rounds to -1, not -2.
When you add these: -3.0 + (-1) promotes -1 to -1.0, giving -4.0.
Students often think (int) casts the entire expression to its right. It does not. It casts only the immediately following value. (int) 2.752 * 10 is 2 * 10 = 20, not (int)(27.52) = 27.
Students often think Math.round(-1.5) returns -2. Java rounds .5 toward positive infinity, so it returns -1. This differs from Math.floor, which would give -2.0.
Students often think == works for comparing String contents. It compares object references. Two Strings created by methods like substring() or toUpperCase() are new objects, so == returns false even when the text is identical. Use .equals() instead.
Students often think integer division rounds. It truncates (discards the fraction). 10 / 3 is 3, not 3.33 or 4. There is no rounding involved, just chopping.
Students often forget to report the correct data type. On this exam, 7.0 for a double, "7" for a String, and '7' for a char are all different answers. Omitting the type marker loses the point.
True or false: 10 / 3 evaluates to 3.33 in Java. (False. Integer division truncates: the result is 3.)
True or false: "hello".toUpperCase() == "HELLO" evaluates to true. (False. toUpperCase() creates a new object, so == returns false.)
Fill in the blank: (int) 4.9 evaluates to ___. (4)
True or false: In the expression "A" + 3 + 4, Java first adds 3 and 4. (False. The String comes first, so both 3 and 4 are concatenated: result is "A34".)
Fill in the blank: Math.floor(-0.1) evaluates to ___. (-1.0)
Q: What does (3 / 2 == 0) + "H" + 2 * 5 + 1.5 evaluate to?
A: "falseH101.5". Step by step: 3 / 2 is 1 (integer division). 1 == 0 is false. false + "H" is "falseH". 2 * 5 is 10 (higher precedence, done before concatenation). "falseH" + 10 is "falseH10". "falseH10" + 1.5 is "falseH101.5".
Q: What does 73983 % 1000 / 100 + 10 * 5 * 1.0 evaluate to?
A: 59.0. Step by step: 73983 % 1000 is 983. 983 / 100 is 9 (integer division). 10 * 5 is 50. 50 * 1.0 is 50.0 (promotion to double). 9 + 50.0 is 59.0.
Q: What does 10 / 3 + 17 % 30 + 2.5 % 2.0 evaluate to?
A: 20.5. Step by step: 10 / 3 is 3. 17 % 30 is 17 (17 is smaller than 30, so the remainder is 17). 2.5 % 2.0 is 0.5. 3 + 17 + 0.5 is 20.5.
Q: What does (int) 2.752 * 10 + 5.0 evaluate to?
A: 25.0. The cast applies only to 2.752, giving 2. Then 2 * 10 is 20. Then 20 + 5.0 is 25.0.
Q: What does "CS312".charAt(2) == '3' evaluate to?
A: true. Index 0 is 'C', index 1 is 'S', index 2 is '3'. '3' == '3' is true.
Q: What does 12 % 3 != 0 || 3 == '3' evaluate to?
A: false. 12 % 3 is 0. 0 != 0 is false. 3 == '3' compares int 3 with the Unicode value of '3', which is 51. 3 == 51 is false. false || false is false.
Q: What does Math.floor(-2.31) + Math.round(-1.5) evaluate to?
A: -4.0. Math.floor(-2.31) is -3.0. Math.round(-1.5) is -1 (rounds toward positive infinity). -3.0 + (-1) is -4.0.
Q: What does "cat".toUpperCase() == "CAT" evaluate to?
A: false. toUpperCase() creates a new String object. == compares references, not content.
Q: What does "longhorns_or+tv".indexOf("or") * 2 evaluate to?
A: 10. The characters are: l(0), o(1), n(2), g(3), h(4), o(5), r(6), n(7), s(8), _(9), o(10), r(11), +(12), t(13), v(14). The first occurrence of "or" is at index 5 (the o at position 5, r at position 6). So 5 * 2 = 10.
Q: What does "super_tas".indexOf("TAs") - 3 evaluate to?
A: -4. "super_tas" does not contain "TAs" (case-sensitive: tas is not TAs). indexOf returns -1. -1 - 3 is -4.
Expression evaluation is the foundation for every code-tracing question on the exam. The same type promotion and integer division rules reappear when tracing loops, array manipulation, and method calls. String reference vs value equality connects directly to the OOP section, where == on objects and overriding .equals() are tested.
Java expression evaluation, operator precedence Java, integer division truncation, type promotion widening, narrowing cast int double, string concatenation +, charAt indexOf substring, == vs equals String, Math.floor Math.round negative, CS 312 UT Austin midterm, CS 307 Java exam, credit by exam Java, modulo remainder operator, boolean short-circuit evaluation