Lesson 3Phase 1: First steps
Operators, expressions, and casting
Arithmetic, comparison, and logic, plus what integer division and type casting really do.
By BasithUpdated 55 min
- arithmetic operators
- integer division
- comparison
- logical operators
- precedence
- casting
You can now put a value in a box and read it back out. On its own that makes a very quiet program. Things get interesting when you combine values: adding two numbers, asking whether one is bigger than another, checking whether two conditions are both true. Operators do that combining, and Java has a few sharp edges here that surprise almost everyone the first time.
- Use the five arithmetic operators and explain exactly what
/and%do. - Predict the result of integer division, and say why
7 / 2is 3 and not 3.5. - Build comparisons and logical expressions that produce a
boolean. - Use a cast to get a decimal answer from whole numbers, to cut a decimal down to a whole number, and to move between a
charand its code. - Spot overflow, when a result is too big for its type, and avoid it with
long. - Use
++,--and shorthand assignments such as+=, and read an expression using the precedence rules.
int, double, boolean and char, and declaring a variable before you use it. Making decisions and repeating work come next, starting with if, else and switch. Here you only build expressions and work out their values.Arithmetic: the five operators#
An expression is any piece of code that Java can work out to a single value. 3 + 4 is an expression; Java evaluates it to 7. The symbols that do the combining, like the + here, are operators. For numbers, Java gives you five:
+addition-subtraction*multiplication/division%remainder, also called modulo
The first three behave the way you expect from school arithmetic. The last two are where the surprises are, so most of this section is about them. Here are the easy ones first.
public class Main { public static void main(String[] args) { int a = 10; int b = 3; System.out.println(a + b); System.out.println(a - b); System.out.println(a * b); }}That prints 13, 7 and 30, one per line. Nothing surprising. Change one operator and the answer stops matching school arithmetic.
The big surprise: integer division#
In ordinary arithmetic, 7 divided by 2 is 3.5. In Java the answer depends on the types involved. Run this and watch the results closely.
public class Main { public static void main(String[] args) { int a = 7; int b = 2; int whole = a / b; int leftOver = a % b; double exact = 7.0 / 2; System.out.println(whole); System.out.println(leftOver); System.out.println(exact); }}Step through it. a / b is 7 / 2, and both a and b are int, so Java does integer division: it divides and throws away everything after the decimal point. 7 / 2 would be 3.5, but the .5 is dropped, so whole is 3. There is no rounding. 3.9 would also become 3; the fraction is cut off.
Then a % b is 7 % 2. The % operator gives the remainder of that same division: 2 goes into 7 three times with 1 left over, so leftOver is 1. Together, whole and leftOver tell the full story: 7 is three 2s with 1 remaining.
The last line is different. 7.0 is a double, not an int. As soon as one side of a division is a decimal, Java does decimal division and keeps the fraction, so 7.0 / 2 is 3.5 and exact prints 3.5. The only difference is the .0 on the first number.
Key ideaIf both sides of
/are whole numbers, you get a whole-number answer with the fraction thrown away. If either side is a decimal, you get a decimal answer. The types of the two sides decide which kind of division happens.
double average = 7 / 2; does not give you 3.5. Java works out 7 / 2 first, while both are still int, gets 3, and only then copies that 3 into the double as 3.0. Declaring the result as a double comes too late: the fraction was lost inside the division. A cast fixes it, further down this page.Remainder is more useful than it looks
Here are a few remainders to build a feel for %. Read each one as “what is left after dividing”.
public class Main { public static void main(String[] args) { System.out.println(17 % 5); System.out.println(20 % 4); System.out.println(5 % 7); System.out.println(13 % 2); }}Walk through them. 17 % 5: five goes into seventeen three times (fifteen) with 2 left, so 2. 20 % 4: four divides twenty exactly, nothing is left, so 0, which is the sign that one number divides another cleanly. 5 % 7: seven does not go into five at all, so the whole 5 is left over. And 13 % 2 is 1 because thirteen is odd. A result of 0 from % 2 means even; 1 means odd.
1234?3725 seconds long. Finish the program so it prints the length as 1 h 2 min 5 s. Work the numbers out with / and %; do not type in the answers.Comparison: questions that answer true or false#
So far the operators take numbers and give back numbers. The next group takes two values and gives back a boolean: either true or false. These are the comparison operators, and they are how a program asks a question.
==equal to (two equals signs, because one already means assignment)!=not equal to<less than, and>greater than<=less than or equal to, and>=greater than or equal to
public class Main { public static void main(String[] args) { int age = 20; boolean isAdult = age >= 18; boolean isExactly20 = age == 20; boolean isTeenager = age < 13; System.out.println(isAdult); System.out.println(isExactly20); System.out.println(isTeenager); }}Each comparison is worked out to a single true or false and stored in a boolean, the type from variables and types. age >= 18 is true, so isAdult is true. age == 20 is true. age < 13 is false, because 20 is not less than 13. The program prints true, true, false.
= is assignment: x = 5 puts 5 into x. == is a question: x == 5 asks whether x holds 5 and answers true or false. Mixing them up is one of the most common early mistakes. When you mean to compare, count the equals signs: you want two.Decimals are close, not exact
A double is stored in binary, and most decimal fractions, such as 0.1, have no exact binary form, in the same way that one third has no exact decimal form (0.333 and so on). So a double holds the nearest value it can, and tiny errors can show up after arithmetic.
public class Main { public static void main(String[] args) { double sum = 0.1 + 0.2; System.out.println(sum); System.out.println(sum == 0.3); }}It prints 0.30000000000000004 and then false. The error is tiny, but == only says true for values that are exactly equal. So avoid == on double results; check instead whether the two are close enough, for example with Math.abs(sum - 0.3) < 0.000001 (Math.abs gives a number without its minus sign). For money, where every cent must come out exact, Java has a separate type, covered in BigDecimal and money.
Logical operators: combining conditions#
Often one question is not enough. “Is the person an adult anda member?” “Is today Saturday or Sunday?” To join booleans you use the logical operators:
&&means and: true only when both sides are true.||means or: true when at least one side is true.!means not: it flips a boolean, turningtrueintofalseand back.
public class Main { public static void main(String[] args) { int age = 25; boolean hasTicket = true; boolean canEnter = age >= 18 && hasTicket; boolean weekend = false || true; boolean isMinor = !(age >= 18); System.out.println(canEnter); System.out.println(weekend); System.out.println(isMinor); }}Trace the first one. age >= 18 is true and hasTicket is true, and && needs both sides true, so canEnter is true. The second, false || true, needs only one side true, so weekend is true. The third takes age >= 18, which is true, and ! flips it, so isMinor is false. The program prints true, true, false.
true exactly when age is a teenager, from 13 to 19 inclusive?Casting: telling Java to change a value's type#
Time to fix the integer division bug, and casting is the tool. A cast tells Java, on purpose, to treat a value as a different type for this one expression. You write the target type in parentheses in front of the value: (double) x means “take x and use it as a doubleright here”.
public class Main { public static void main(String[] args) { int total = 7; int count = 2; double wrong = total / count; double right = (double) total / count; double careful = (double) (total / count); System.out.println(wrong); System.out.println(right); System.out.println(careful); }}The three lines give three different answers. wrong is the trap from earlier: total / count is 7 / 2 with both still int, so it is 3, and copying that into a double gives 3.0. The fraction was gone before the double ever saw it.
right is the fix. (double) total turns 7 into 7.0 before the division, so the division sees a decimal on the left and does decimal division: 7.0 / 2 is 3.5. You only need to cast one side; Java converts the other to match. This is the pattern to remember for averages and percentages.
careful shows why position matters. The parentheses force total / count to happen first, while both are still int, giving 3, and only then is that 3 cast to 3.0. So it prints 3.0, the same as wrong. (double) total / count and (double) (total / count) are not the same: cast a value before it is divided, not the answer after.
Key ideaTo get a decimal answer from integer division, cast one side to
doublebefore the/.(double) a / bworks;(double) (a / b)is too late.
Casting the other way: chopping a decimal down to an int
Casts work in both directions. Putting (int) in front of a double does the opposite job: it truncates, cutting off everything after the decimal point, with no rounding.
public class Main { public static void main(String[] args) { double price = 9.99; int dollars = (int) price; double almostFour = 3.99; int chopped = (int) almostFour; System.out.println(dollars); System.out.println(chopped); }}(int) 9.99 is 9, and (int) 3.99 is 3. Java does not round to the nearest whole number; it drops the fraction. For real rounding there is Math.round: Math.round(3.99) gives 4.
double d = 5; works with no cast, because every int fits in a double, and d becomes 5.0. You need a cast only when information might be lost, such as squeezing a double into an intand dropping the fraction. The cast is you confirming: “yes, I know I might lose something here”.Casting between char and its number
From variables and types you know that a char is really a small number underneath, the code that stands for a character. Casting lets you cross between the character and that number on purpose.
public class Main { public static void main(String[] args) { char letter = 'A'; int code = (int) letter; char fromCode = (char) 66; char next = (char) (letter + 1); System.out.println(code); System.out.println(fromCode); System.out.println(next); }}(int) 'A' asks for the code behind the letter A, which is 65, so code is 65. Going back, (char) 66 asks for the character whose code is 66, which is B. And (char) (letter + 1) adds 1 to the code of A, giving 66, and the cast turns that back into the letter B. So the program prints 65, B, B. The letters of the alphabet sit in order by code, which is why adding one steps to the next letter.
System.out.println('A' + 1); print?Average: 8.333333333333334, but it prints Average: 8.0. Fix the line that works out average.When a number does not fit: overflow#
An int holds whole numbers up to 2147483647, a little over two billion. What happens when a calculation goes past that?
public class Main { public static void main(String[] args) { int big = 2147483647; int bigger = big + 1; System.out.println(bigger); long safe = big + 1L; System.out.println(safe); }}big + 1 does not give 2147483648, and the program does not stop. The result wraps around to the most negative int, -2147483648, like a car's mileage counter that runs out of digits and starts again, except that an int starts again from the bottom of its range. This is called overflow, and Java gives no warning when it happens. The second calculation adds 1L, a long, so Java works out the sum as a long, which has plenty of room: 2147483648.
Storing the answer in a long is not enough on its own. Decide what this prints before you run it.
public class Main { public static void main(String[] args) { long msPerMonth = 30 * 24 * 60 * 60 * 1000; System.out.println(msPerMonth); }}This works out the milliseconds in 30 days and stores them in a long, which can hold numbers far bigger than an int. What does it print?
It prints -1702967296. All five numbers are int literals, so Java multiplies them as int values. The true answer, 2,592,000,000, is too big for an int, so the multiplication overflows, and only the wrapped result is copied into the long. It is the same trap as double average = 7 / 2;. The fix is the same too: make one number in the calculation the bigger type from the start. 30L * 24 * 60 * 60 * 1000 is worked out as a long and gives 2592000000.
Key ideaJava works out an expression with the types inside it, and only then stores the result. Declaring the variable as
doubleorlongcomes too late to save a division or a multiplication already done inint.
Counting up and down: ++ and --#
Adding one to a variable is so common that Java gives it a shorthand. x++means “increase x by one”, exactly like writing x = x + 1;. Its partner x-- decreases by one. These are the increment and decrement operators, and you will see them constantly once you reach loops.
public class Main { public static void main(String[] args) { int x = 5; x++; System.out.println(x); x--; x--; System.out.println(x); }}Starting at 5, one x++ makes it 6, then two x-- bring it down to 4. Each one moves the value by exactly one.
Before or after: the pre and post forms
There is a subtlety worth seeing once. You can write the operator before the variable (++x, the prefix form) or after it (x++, the postfix form). The variable ends up increased either way. The difference shows only when you use the result in the same statement: ++x increases first and then hands back the new value, while x++ hands back the old value and then increases.
public class Main { public static void main(String[] args) { int a = 5; int afterPost = a++; // hands back 5, THEN a becomes 6 System.out.println(afterPost); // 5 System.out.println(a); // 6 int b = 5; int afterPre = ++b; // b becomes 6 FIRST, then hands back 6 System.out.println(afterPre); // 6 System.out.println(b); // 6 }}x++ sits on its own line, as a whole statement, the two forms behave the same: both add one. The difference only shows when you use the result in the same statement. Until you have a reason, write the plain x++; on its own line, which is the common case in loops.Shorthand assignments: += and friends#
Just as x++ shortens x = x + 1, Java shortens the pattern “change a variable using its own current value” for every arithmetic operator. x += 3 means x = x + 3, and the others follow the same pattern. These are called compound assignment operators.
x += 3x = x + 3x -= 3x = x - 3x *= 3x = x * 3x /= 3x = x / 3x %= 3x = x % 3public class Main { public static void main(String[] args) { int total = 10; total += 5; System.out.println(total); total *= 2; System.out.println(total); total -= 3; System.out.println(total); }}Starting at 10: += 5 makes it 15, *= 2 makes it 30, and -= 3 makes it 27. Each shorthand reads the current value, applies the operator, and stores the result back in the same variable.
To pay: 100.Tap a line, then tap where it should go. Or use the arrows.
Precedence: which operator goes first#
When several operators sit in one expression, Java needs a rule for the order. For arithmetic it is the order you know from school: multiplication and division happen before addition and subtraction. This ordering is called precedence.
public class Main { public static void main(String[] args) { System.out.println(2 + 3 * 4); System.out.println((2 + 3) * 4); System.out.println(10 - 4 - 3); System.out.println(20 / 4 * 2); }}First line: * binds more tightly than +, so Java does 3 * 4 to get 12, then 2 + 12 is 14. Second line: the parentheses override that and force 2 + 3 first, giving 5, then 5 * 4 is 20. Parentheses always win, which is what makes them so useful.
The last two lines show what happens when operators are on the same level. Then Java works from left to right. 10 - 4 - 3 is (10 - 4) - 3, which is 6 - 3, which is 3. And 20 / 4 * 2 is (20 / 4) * 2, which is 5 * 2, which is 10: * and / share a level, so neither jumps ahead; they go in reading order.
| Order | Operators | Example |
|---|---|---|
| 1, first | x++ x-- | count++ |
| 2 | ++x --x, a minus sign in front, !, and casts such as (int) | -x, !done, (double) a |
| 3 | * / % | a * b |
| 4 | + - | a + b |
| 5 | < > <= >= | age >= 18 |
| 6 | == != | x == 5 |
| 7 | && | a && b |
| 8 | || | a || b |
| 9, last | = += -= *= /= %= | total += 5 |
Left to right and integer division together make a good puzzle. Try it before you run it.
public class Main { public static void main(String[] args) { System.out.println(1 / 2 * 10); System.out.println(10 * 1 / 2); System.out.println(1.0 / 2 * 10); }}The same three numbers, in a different order. What do the three lines print?
1 / 2 is integer division, so it gives 0, and 0 * 10 is 0. In 10 * 1 / 2 the multiplication comes first, because it is on the left, giving 10, and 10 / 2 is 5. In the last line 1.0 makes the division decimal: 0.5 * 10 is 5.0. When integer division is involved, the order of the steps changes the answer.
Try it
Answer each one in your head or on paper first, then open the answer.
9 / 2 print, and what does 9 % 2 print? Say why each is what it is.double avg = 5 / 2; expecting 2.5, but it prints 2.0. What went wrong, and how do you fix it with a cast?2 + 6 / 2 by hand. Then work out (2 + 6) / 2. Are they the same?age >= 13 && age <= 19 give when age is 16? And when age is 21?(char) ('a' + 2) give, if the code for 'a' is 97?Practice
Work through these on your own. Each one builds on this page.
int n = 4729;. Using only % and /, print its digits one per line from the last to the first: 9, 2, 7, 4. You will repeat the same two steps four times; loops, which do the repeating for you, are coming soon.(98 - 32) * 5 / 9 degrees Celsius. Print that expression as it stands, then change it so the answer keeps its fraction. What does each version print, and why do they differ?10 % 3 + 4 * 2 - 1 step by step, writing down each intermediate result and the precedence rule you used. Then run it and check that your answer matches.char grade = 'C';. Write code that prints the letter two grades better (so the letter A) by casting between char and its code. Then, in a comment, explain in one sentence why the (char) cast is needed and what prints if you leave it out.int numbers and once with a long, print both, and explain in a sentence why one of them is negative.Further reading#
- Using operators in your programs, on dev.java, the official Java learning site
- A summary of every Java operator, on dev.java
- The division operator in the Java Language Specification for Java SE 25, section 15.17.2, the exact rules for integer division and division by zero
- Conversions and contexts, chapter 5 of the Java Language Specification, which defines widening and narrowing
Spotted a mistake, or a part that did not make sense? Report it by email