Java Return Values

Su Suriya Ravichandran Updated 14 Nov 2026
6 min read ·Lesson 26 of 133

A return value is the result a method sends back to the code that called it. Returning a value, rather than printing it or storing it in a shared variable, makes a method a reusable building block: the caller decides what to do with the result.

The return Statement

static int square(int n) {
    return n * n;
}

int a = square(4);                       // 16
int b = square(3) + square(4);           // 25
System.out.println(square(square(2)));   // 16

The declared return type (int) states what kind of value the method produces. return n * n; evaluates the expression and hands the result back. The call square(4) is itself an expression, so it can be assigned, combined with other expressions, or passed directly to another method.

The returned value must be compatible with the declared type:

static int half(int n) {
    return n / 2.0;    // compile error: double cannot be converted to int
}

Widening is automatic: a method declared to return double may return 5;.

void Methods

A method that produces no result declares the return type void:

static void logMessage(String msg) {
    System.out.println("[LOG] " + msg);
}

It cannot be used as a value: String s = logMessage("x"); does not compile. A void method may use a bare return; to finish early:

static void sendReminder(String email) {
    if (email == null || email.isBlank()) {
        return;                      // nothing to do
    }
    System.out.println("Sending reminder to " + email);
}

return Ends the Method Immediately

Any statements after a return on the same path do not run. The compiler rejects code that can never be reached:

static int sign(int n) {
    return n > 0 ? 1 : -1;
    System.out.println("done");   // compile error: unreachable statement
}

Several return statements in one method are normal. Each returns from a different path:

static String classify(int age) {
    if (age < 0) {
        return "invalid";
    }
    if (age < 13) {
        return "child";
    }
    if (age < 20) {
        return "teen";
    }
    return "adult";
}

Because each return exits, no else is needed: reaching the second if already implies age >= 0. This early-return style keeps methods flat.

Every Path Must Return

For a non-void method, the compiler verifies that every possible path ends in a return (or a throw):

static String grade(int score) {
    if (score >= 50) {
        return "pass";
    } else if (score < 50) {
        return "fail";
    }
}   // compile error: missing return statement

To a human the two conditions cover everything, but the compiler does not reason about numeric ranges; it sees an if/else if with no final else. Use a plain else, or a final return after the chain.

A throw also satisfies the rule, which is how methods handle impossible or invalid cases:

static double divide(double a, double b) {
    if (b == 0) {
        throw new ArithmeticException("Division by zero");
    }
    return a / b;
}

Return Instead of Print

Compare two versions of the same calculation:

static void printAverage(int[] values) {
    int sum = 0;
    for (int v : values) sum += v;
    System.out.println((double) sum / values.length);
}

static double average(int[] values) {
    int sum = 0;
    for (int v : values) sum += v;
    return (double) sum / values.length;
}

printAverage can only print. average can be printed, formatted, compared, stored, written to a file, sent in an HTTP response, or checked in a unit test:

double avg = average(scores);
if (avg < 40) sendWarning();
System.out.printf("Average: %.1f%n", avg);

Separating computation from output is one of the most useful habits in program design.

Returning Objects and Arrays

A method can return any type, including arrays, collections, and your own classes:

static int[] minMax(int[] values) {
    int min = values[0], max = values[0];
    for (int v : values) {
        if (v < min) min = v;
        if (v > max) max = v;
    }
    return new int[]{min, max};
}

int[] r = minMax(new int[]{7, 2, 9, 4});
System.out.println(r[0] + " to " + r[1]);   // 2 to 9

This works, but the caller must remember that index 0 is the minimum. A record makes the result self-describing:

record Range(int min, int max) {}

static Range minMax(int[] values) {
    int min = values[0], max = values[0];
    for (int v : values) {
        min = Math.min(min, v);
        max = Math.max(max, v);
    }
    return new Range(min, max);
}

Range r = minMax(new int[]{7, 2, 9, 4});
System.out.println(r.min() + " to " + r.max());   // 2 to 9

Java methods return exactly one value. When several values belong together, return an object that groups them.

Returning "No Result"

Methods that search for something must decide what to return when nothing is found.

A sentinel value is a special value that cannot be a real result, such as -1 for an index:

int idx = "hello".indexOf('z');   // -1

This is fine when an obvious impossible value exists.

null is common for objects but pushes the burden onto the caller, who must remember to check:

User u = findUser("ada");
System.out.println(u.getName());   // NullPointerException if not found

Optional makes the possibility of absence part of the return type:

import java.util.Optional;

static Optional<String> findEmail(String username) {
    if (username.equals("ada")) {
        return Optional.of("ada@example.com");
    }
    return Optional.empty();
}

String email = findEmail("bob").orElse("no email on file");
findEmail("ada").ifPresent(e -> System.out.println("Mail to " + e));

The caller cannot treat the result as a plain String without deciding what happens when it is empty. Optional is intended for return values; it has its own lesson.

For collections, return an empty collection rather than null. List.of() or Collections.emptyList() lets callers loop over the result without a null check.

Returning a Reference to Internal State

Returning a mutable internal object lets callers modify it behind the class's back:

public class Course {
    private final List<String> students = new ArrayList<>();

    public List<String> getStudents() {
        return students;                    // caller can add or remove students
    }

    public List<String> getStudentsSafe() {
        return List.copyOf(students);       // read-only snapshot
    }
}
course.getStudents().clear();       // empties the course's real list
course.getStudentsSafe().clear();   // UnsupportedOperationException

Return an unmodifiable view or copy when callers should only read the data. This is part of encapsulation, covered in the OOP section.

Practical Example: Password Strength Checker

public class PasswordCheck {
    record Result(int score, String verdict) {}

    static boolean hasDigit(String s) {
        for (char c : s.toCharArray()) {
            if (Character.isDigit(c)) return true;
        }
        return false;
    }

    static boolean hasUpper(String s) {
        for (char c : s.toCharArray()) {
            if (Character.isUpperCase(c)) return true;
        }
        return false;
    }

    static boolean hasSymbol(String s) {
        for (char c : s.toCharArray()) {
            if (!Character.isLetterOrDigit(c)) return true;
        }
        return false;
    }

    static Result evaluate(String password) {
        if (password == null || password.length() < 8) {
            return new Result(0, "Too short");
        }
        int score = 1;
        if (hasDigit(password)) score++;
        if (hasUpper(password)) score++;
        if (hasSymbol(password)) score++;
        if (password.length() >= 12) score++;

        String verdict = switch (score) {
            case 1, 2 -> "Weak";
            case 3 -> "Fair";
            case 4 -> "Strong";
            default -> "Very strong";
        };
        return new Result(score, verdict);
    }

    public static void main(String[] args) {
        String[] tests = {"abc", "password", "Password1", "Pass word#2026"};
        for (String p : tests) {
            Result r = evaluate(p);
            System.out.printf("%-15s %d %s%n", p, r.score(), r.verdict());
        }
    }
}

Output:

abc             0 Too short
password        1 Weak
Password1       3 Fair
Pass word#2026  5 Very strong

The has... helpers return true the moment they find a match, so they stop scanning early, and return false only after checking every character. evaluate returns early for a password that is too short, then returns a Result record carrying both the numeric score and the label. Because nothing is printed inside these methods, the same checker could feed a web form's validation message or a unit test unchanged.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Java Return Values and get answers drawn from it.

Signed-in readers only.