Java Type Casting and the var Keyword

Java type casting converts a value to another compatible type.

Lesson 8 of 127Beginner14 min read

Java type casting converts a value to another compatible type. Some numeric conversions happen automatically, while others require an explicit cast because information may be lost. The var keyword solves a different problem: it asks the compiler to infer a local variable’s type from its initializer. It does not create a dynamically typed variable.

This distinction matters when a calculation produces an unexpected answer. Check whether conversion happened before or after the calculation, and whether the destination can represent the source value. The examples use Java 17; local var declarations have been available since Java 10.

Widening conversion and precision

Java automatically permits many conversions from a narrower numeric type to a wider one. An int value can initialize a long or double variable without an explicit cast. A long has enough range to represent every int value exactly. A double also represents every int exactly, but converting a long to double can lose precision even though this conversion is permitted.

Widening therefore does not universally mean that every bit of information survives. Range and precision are separate properties. Floating-point types can represent extremely large magnitudes while still being unable to distinguish neighboring large integers. When identifiers, money amounts or exact counts must remain exact, avoid treating an allowed numeric conversion as proof that the resulting representation preserves their meaning.

Narrowing requires a deliberate choice

An explicit cast uses a target type in parentheses, such as (int) measurement. Casting a finite double to int discards its fractional part toward zero, so 7.9 becomes 7 and -7.9 becomes -7. This is not the same as rounding to the nearest integer. Values outside the int range have defined conversion behavior, but applications should validate their permitted range rather than relying on those boundary results.

Narrowing between integer types can keep only the low-order bits. Casting 130 to byte produces -126 because byte cannot represent 130. A cast is an instruction to perform conversion, not a validation that the original value was sensible. Use a range check or a checked conversion such as Math.toIntExact when an out-of-range value should cause a failure.

Cast before the operation you want to change

Java determines numeric arithmetic from the operands. In (double) 5 / 2, the cast makes the first operand double, so division produces 2.5. In (double) (5 / 2), integer division first produces 2 and the later cast produces 2.0. Parentheses make this order visible.

The same principle applies to avoiding multiplication overflow. Casting one operand to long before multiplication changes the arithmetic type; casting a finished int product does not restore information already lost. Write an intermediate variable if the expression becomes difficult to read. A descriptive name such as averageDistance can clarify the intended unit, but the name itself does not influence the type or conversion rules.

var infers one fixed local type

With var count = 6;, the compiler infers int from the initializer. Later assigning 7 is valid, but assigning "seven" is not. Type inference happens during compilation and leaves a fixed static type. You must provide an initializer, and var value = null is invalid because null alone does not identify a useful inferred type.

Use var for local variables when the right-hand side makes the type clear, such as var names = new java.util.ArrayList<String>();. It is not permitted as a field type, a method return type or an ordinary method parameter type. Some lambda parameter forms allow var under their own rules, which is a separate feature. Avoid replacing helpful explicit types with var when the initializer hides whether a result is a list, stream, number or reference.

Casting cannot parse text or bypass compatibility

A numeric cast does not turn the string "42" into an int. Use Integer.parseInt for text containing an integer and handle invalid input appropriately. Likewise, String.valueOf converts many values to text; that is a library operation rather than a primitive cast to String.

Reference casts are about object type relationships. A cast cannot turn an unrelated object into whatever class you wish. A reference downcast can compile yet fail at runtime if the actual object does not have the required type. Primitive casts and reference casts share the parenthesized notation but follow different rules. Learn reference casting with inheritance; for numeric lessons, keep the focus on arithmetic types, accepted ranges and the point at which conversion occurs.

Practice with explained solutions

Task 1. Calculate 11 divided by 4 as a double without changing the integer variable declarations.

Solution. Cast one operand: (double) numerator / denominator produces 2.75. Casting the completed integer division produces 2.0 instead.

Task 2. Explain why var item = null cannot compile and provide a valid alternative for optional text.

Solution. Use String item = null; when a nullable String is intentional. The explicit type supplies information that a null initializer lacks.

Java Summary

  • Cast before the calculation whose arithmetic type needs to change.
  • Narrowing can discard fractions or high bits; validate the permitted range separately.
  • var infers one fixed local type from its initializer.
  • Continue with operators and precedence.

Java Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Conversion before and after division

Save this complete program as DivisionCasting.java. Compile with javac --release 17 DivisionCasting.java and run with java DivisionCasting.

Java
public class DivisionCasting {
    public static void main(String[] args) {
        double before = (double) 5 / 2;
        double after = (double) (5 / 2);
        System.out.println(before);
        System.out.println(after);
    }
}
Output
2.5
2.0
Line-by-line explanation
  1. Lines 1 to 8before uses floating-point division because its first operand is converted first. after receives an already truncated integer quotient converted to double. Both variables have the same declared type, yet their values differ because the expressions use different arithmetic. Inspecting only the declaration cannot explain the result; the cast’s location is the deciding detail.
Example 2

See the effect of narrowing

Save this complete program as NarrowingValues.java. Compile with javac --release 17 NarrowingValues.java and run with java NarrowingValues.

Java
public class NarrowingValues {
    public static void main(String[] args) {
        double measured = -7.9;
        int whole = (int) measured;
        byte small = (byte) 130;
        System.out.println(whole);
        System.out.println(small);
    }
}
Output
-7
-126
Line-by-line explanation
  1. Lines 1 to 9The double-to-int conversion truncates toward zero, yielding negative seven rather than negative eight. The int-to-byte cast retains the relevant low bits and interprets them in the signed byte range. Neither conversion throws an exception for these values. Validate values before narrowing if the application requires a positive small number rather than merely the language’s defined conversion.
Example 3

Use inferred local types

Save this complete program as InferredLocals.java. Compile with javac --release 17 InferredLocals.java and run with java InferredLocals.

Java
public class InferredLocals {
    public static void main(String[] args) {
        var count = 6;
        var label = "Packages";
        count = 7;
        System.out.println(label + ": " + count);
    }
}
Output
Packages: 7
Line-by-line explanation
  1. Lines 1 to 8The integer literal makes count an int, and the string literal makes label a String. Reassigning count to seven fits its inferred type. Reassigning it to a string would not compile. var saves the written type name but does not make the variable accept arbitrary values or postpone type checking until execution.

Common Java Mistakes

Adding casts just to silence the compiler

Do not add casts until a compiler error disappears without checking what information they discard. If a method expects int but your calculation produces long, decide whether the permitted input truly fits int. A checked conversion documents that assumption more clearly than silently narrowing. For var, keep explicit types where they reveal an important distinction, especially numeric precision.

Java FAQ

Does var improve runtime speed?

It changes source syntax, not the fundamental execution model. The compiler still knows a static type.

Is an explicit cast always safe?

No. Numeric casts can lose information, and reference casts can fail at runtime. Use casts only when their preconditions and consequences are understood.

What is the difference between casting and parsing?

Casting converts between compatible types, such as double to int or a parent reference to a subclass. Parsing reads text and builds a value from it, such as Integer.parseInt("42"). You can't cast a String to a number; you have to parse it.

What happens when a large double is cast to int?

Values beyond the int range are clamped to the nearest limit, so (int) 1e10 is 2147483647, and NaN becomes 0. Casting between integer types works differently: (byte) 200 keeps only the lowest eight bits and gives -56. Check the range first when the value might not fit.

Where can var be used in Java?

Only for local variables that are initialised in the same statement, in for loops and, since Java 11, for lambda parameters. It can't be used for fields, method parameters or return types, and var x = null; doesn't compile because there's no type to infer.

Java Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

What does (double) (5 / 2) produce?

Multiple choicemedium

Which var declaration is valid?

Java Quiz

2 questions to check what you learned.

  1. What is inferred for var count = 6?

    • int
    • Object
    • A changing dynamic type
  2. What does (int) -7.9 produce?

    • -7
    • -8
    • A rounded value chosen randomly