Java variables practice — the mistakes everyone makes with types
There’s a moment in the first Java lab that happens to almost everyone. You’ve been writing code for a while, you get to a division, you run the program and the result is… 3. Not 3.5. Not 3.33. Three. A whole number. The number you expected was right there on paper, but Java decided to truncate it without warning.
That’s integer division. And it’s just one of three surprises waiting for you when you start mixing types in Java. In this practice we’re going to trigger all three on purpose — so when they show up in the lab you already know them.
Open VS Code and create a folder variables_practice. One .java file for each program.
Table of Contents
Java variables practice — Program 1: Calculator with mixed types
Why start with a calculator if we already made one in the syntax practice? Because this one is different — the goal here isn’t the result, it’s understanding what happens when you mix int and double without thinking.
import java.util.Scanner;
public class CalculatorTypes {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== CALCULATOR WITH TYPES ===");
System.out.println();
System.out.print("First number (integer): ");
int a = sc.nextInt();
System.out.print("Second number (integer): ");
int b = sc.nextInt();
System.out.println();
System.out.println("--- Division: the big surprise ---");
// Integer division — Java's default behaviour
int intDiv = a / b;
System.out.printf("%d / %d = %d ← INTEGER division%n", a, b, intDiv);
// Real division — you need at least one double
double realDiv1 = (double) a / b;
System.out.printf("%d / %d = %.4f ← cast before dividing%n",
a, b, realDiv1);
double realDiv2 = a / (double) b;
System.out.printf("%d / %d = %.4f ← cast on divisor%n",
a, b, realDiv2);
double realDiv3 = (double)(a / b);
System.out.printf("%d / %d = %.4f ← cast AFTER (trap!)%n",
a, b, realDiv3);
System.out.println();
System.out.println("--- Integer overflow ---");
int limit = Integer.MAX_VALUE;
System.out.printf("Max int: %,d%n", limit);
System.out.printf("Max int + 1: %,d ← overflow%n", limit + 1);
long bigLimit = Integer.MAX_VALUE + 1L;
System.out.printf("With long: %,d ← correct%n", bigLimit);
System.out.println();
System.out.println("--- Automatic widening ---");
int integer = 42;
long big = integer; // automatic
double dec = integer; // automatic — 42.0
System.out.printf("int: %d%n", integer);
System.out.printf("long: %d ← automatic widening%n", big);
System.out.printf("double: %.1f ← automatic widening%n", dec);
sc.close();
}
}
Run it with a = 7 and b = 2 and look at the fourth line of results:
7 / 2 = 3 ← INTEGER division 7 / 2 = 3.5000 ← cast before dividing 7 / 2 = 3.5000 ← cast on divisor 7 / 2 = 3.0000 ← cast AFTER (trap!)
The last line is the trap most people don’t see coming. (double)(a / b) converts the result to double, but the division already happened as integer — the damage is done. The cast must go before the operation, not after.
And if you ever see a large negative number where you expected a large positive one — that’s overflow. Integer.MAX_VALUE + 1 gives -2147483648 because the integer wraps around. The fix is to use long.
Java variables practice — Program 2: Temperature converter with casting
Temperatures are perfect for practising casting because the formulas constantly mix integers and decimals. There’s also a real physical constraint here: you can’t go below absolute zero.
import java.util.Scanner;
public class TemperatureConverter {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== TEMPERATURE CONVERTER ===");
System.out.println();
System.out.println("Convert from:");
System.out.println("1. Celsius (°C)");
System.out.println("2. Fahrenheit (°F)");
System.out.println("3. Kelvin (K)");
System.out.print("Option: ");
int option = sc.nextInt();
System.out.print("Temperature: ");
double temp = sc.nextDouble();
// Convert to Celsius first
double celsius;
String sourceUnit;
switch (option) {
case 1:
celsius = temp;
sourceUnit = "°C";
break;
case 2:
celsius = (temp - 32) * 5.0 / 9.0;
sourceUnit = "°F";
break;
case 3:
celsius = temp - 273.15;
sourceUnit = "K";
break;
default:
System.out.println("Invalid option");
sc.close();
return;
}
// Absolute zero: -273.15°C
if (celsius < -273.15) {
System.out.println("Temperature below absolute zero — impossible");
sc.close();
return;
}
// Convert to the other two
double fahrenheit = celsius * 9.0 / 5.0 + 32;
double kelvin = celsius + 273.15;
// Integer version — truncated, not rounded
int celsiusInt = (int) celsius;
int fahrenheitInt = (int) fahrenheit;
int kelvinInt = (int) kelvin;
System.out.println();
System.out.printf("%.2f %s equals:%n", temp, sourceUnit);
System.out.println();
System.out.printf(" Celsius: %8.2f °C%n", celsius);
System.out.printf(" Fahrenheit: %8.2f °F%n", fahrenheit);
System.out.printf(" Kelvin: %8.2f K%n", kelvin);
System.out.println();
System.out.println("--- As integer (casting to int — truncates, does not round) ---");
System.out.printf(" Celsius: %d °C%n", celsiusInt);
System.out.printf(" Fahrenheit: %d °F%n", fahrenheitInt);
System.out.printf(" Kelvin: %d K%n", kelvinInt);
// Reference points
System.out.println();
System.out.println("--- Reference temperatures ---");
System.out.printf(" Absolute zero: -273.15 °C = %.2f °F = 0 K%n",
-273.15 * 9.0 / 5.0 + 32);
System.out.printf(" Water freezes: 0.00 °C = 32.00 °F = 273.15 K%n");
System.out.printf(" Water boils: 100.00 °C = 212.00 °F = 373.15 K%n");
System.out.printf(" Human body: 37.00 °C = %.2f °F = %.2f K%n",
37.0 * 9.0 / 5.0 + 32, 37.0 + 273.15);
sc.close();
}
}
Try it with 100 Celsius — you should get exactly 212 Fahrenheit and 373.15 Kelvin. If the numbers don’t add up, check that your formulas use 5.0 and 9.0 instead of 5 and 9. Why? Because 5/9 in Java is 0 — integer division again. That decimal point changes everything.
Java variables practice — Program 3: Product card with String
Here comes the third surprise: == vs .equals(). This program works with real Strings — it reads them from the user, compares them, manipulates them — and at some point you’ll see why comparing Strings with == is one of those things that seems to work… until it doesn’t.
import java.util.Scanner;
public class ProductCard {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("=== PRODUCT CARD ===");
System.out.println();
System.out.print("Product name: ");
String name = sc.nextLine();
System.out.print("Category (electronics/clothing/home): ");
String category = sc.nextLine();
System.out.print("Price (€): ");
double price = sc.nextDouble();
System.out.print("Stock available: ");
int stock = sc.nextInt();
sc.nextLine();
System.out.print("Product code (e.g. PROD-001): ");
String code = sc.nextLine();
// Calculations with types
double priceWithVAT = price * 1.21;
double salePrice = price * 0.85; // 15% discount
boolean available = stock > 0;
boolean lowStock = stock > 0 && stock < 5;
// String operations
String nameUpper = name.toUpperCase();
String cleanCode = code.trim().toUpperCase();
int nameLength = name.length();
char firstLetter = name.charAt(0);
String categoryFmt = category.trim().toLowerCase();
// Category classification
String icon;
if (categoryFmt.equals("electronics")) {
icon = "💻";
} else if (categoryFmt.equals("clothing")) {
icon = "👕";
} else if (categoryFmt.equals("home")) {
icon = "🏠";
} else {
icon = "📦";
}
// Display card
System.out.println();
System.out.println("╔══════════════════════════════╗");
System.out.printf( "║ %s %-24s║%n", icon, nameUpper);
System.out.println("╠══════════════════════════════╣");
System.out.printf( "║ Code: %-17s║%n", cleanCode);
System.out.printf( "║ Category: %-17s║%n", categoryFmt);
System.out.printf( "║ Price: %8.2f € ║%n", price);
System.out.printf( "║ With VAT: %8.2f € ║%n", priceWithVAT);
System.out.printf( "║ On sale: %8.2f € ║%n", salePrice);
System.out.printf( "║ Stock: %-17d║%n", stock);
System.out.println("╠══════════════════════════════╣");
System.out.printf( "║ Available: %-15s║%n", available ? "YES ✓" : "NO ✗");
System.out.printf( "║ Low stock: %-15s║%n", lowStock ? "WARNING ⚠" : "---");
System.out.println("╚══════════════════════════════╝");
System.out.println();
System.out.println("--- Name analysis ---");
System.out.printf("Original: %s%n", name);
System.out.printf("Uppercase: %s%n", nameUpper);
System.out.printf("Length: %d characters%n", nameLength);
System.out.printf("First letter: %c%n", firstLetter);
// The == trap
System.out.println();
System.out.println("--- The == trap with Strings ---");
String cat1 = "electronics";
String cat2 = category.trim().toLowerCase();
System.out.printf("cat1 == cat2: %b ← may fail%n", cat1 == cat2);
System.out.printf("cat1.equals(cat2): %b ← always correct%n",
cat1.equals(cat2));
sc.close();
}
}
Try it with “Gaming Laptop”, “electronics”, 899.99, 3 and “prod-001”. Pay attention to the last section — depending on how Java manages memory internally, == can return true or false for the same content. It’s not predictable. .equals() always works. No debate.
Visualise with Python Tutor
Select Java from the dropdown and paste in pythontutor.com:
public class TypesDemo {
public static void main(String[] args) {
// Integer vs real division
int a = 7, b = 2;
int intDiv = a / b;
double realDiv = (double) a / b;
System.out.println("Integer: " + intDiv);
System.out.println("Real: " + realDiv);
// Casting
double price = 9.99;
int priceInt = (int) price;
System.out.println("Price: " + price);
System.out.println("Price int: " + priceInt);
// String and equals
String s1 = "hello";
String s2 = new String("hello");
System.out.println("== : " + (s1 == s2));
System.out.println("equals(): " + s1.equals(s2));
}
}
Step through carefully. When you reach (double) a / b, watch how a is temporarily converted to 7.0 before dividing — the original variable doesn’t change, the cast only affects that one operation. When you reach (int) price you’ll see 9.99 become 9 — truncated, not rounded. And when you get to the == with Strings, Python Tutor shows you the memory arrows: s1 and s2 point to different objects even though they contain the same text, which is why == is false.
Summary and next step
Three programs, three surprises resolved. Integer division happens when both operands are int — put the cast before the operation. Casting to int truncates, it doesn’t round — if you need rounding use Math.round(). And Strings are always compared with .equals(), never with ==.
In the next article you’ll find exercises to solve on your own.
Next step: exercisesJava variables exercises — master types, casting and Strings
One Comment