Java Methods and Return Values
Give one operation a clear name, supply its inputs, and use its result. Learn to trace calls and keep calculations reusable instead of burying every decision and print statement inside main.
Before you start: review arrays and summaries, branching, and loop exits. Examples use the Java 21 runner. Predict the call order and returned value before running each program.
What you will be able to do
- Declare a helper method inside a class but outside other methods.
- Trace a call from its arguments through its body and back to the caller.
- Distinguish a returned value from console output and from void.
- Return a compatible result on every normally completing path.
- Keep calculation methods separate from input and presentation.
- Test reusable methods with ordinary, empty, invalid, and boundary cases.
A method gives one operation a name
As a program grows, main can become a long mixture of validation, loops, calculations, and printing. A method names one operation so callers can request it without repeating its implementation. A useful name explains the task: showPracticeTip describes an action more clearly than an arbitrary name such as doStuff.
The first example declares showPracticeTip once and calls it twice. Each call executes its body again; the declaration alone does not print anything. main prints its first line, transfers control to the helper, resumes after that call, calls the helper again, and finally prints its last line.
The helper sits inside class Main but outside main's braces. Java does not allow an ordinary method declaration inside another method. Its position below main does not make it run later automatically: calls, not the order of declarations on the page, decide when these helper bodies execute.
Main.java · Declare once and call twice
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Before calls
Try one small example.
Try one small example.
After calls
Read the method header as a small promise
In static int doubleMinutes(int minutes), doubleMinutes is the name, int minutes declares one input parameter, and the int before the name declares the result type. The body returns minutes * 2. The method promises an int result when it completes normally, not a particular console message.
The methods in this lesson are static so static main can call them directly without first creating an object. They belong to the class rather than requiring a particular instance. This is a teaching setup for small calculations, not a claim that every real method should be static; instance behavior arrives in the classes lessons.
The parameter is a named input inside the helper; the argument is the value or expression supplied at the call site. doubleMinutes(planned) supplies the current value of planned, here 15. The next lesson studies parameter passing in depth. For now, focus on matching the number and types of arguments to the declaration.
Main.java · Capture a returned result
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Planned: 15
Doubled: 30
With a five-minute break: 35
A returned value takes the place of the call expression
Trace int doubled = doubleMinutes(planned) in order. The argument value is obtained, the helper body computes its result, return hands that result back, and the caller assigns it to doubled. The helper does not gain the right to read every unrelated local variable in main just because main called it.
Once doubled contains 30, main can print it, add five to it, compare it, or pass it to another operation. This is why returning useful data makes a calculation reusable. A call is not limited to appearing inside println, and printing the same number is not a substitute for returning it.
Use an intermediate variable when it makes the steps easier to inspect. A short nested call can be convenient, but packing several calculations into a single printing expression can hide which argument or result is wrong. Predict each returned value independently before looking at the final formatted output.
Trace doubleMinutes(15) back to its caller
- The caller supplies the int value 15.
- The parameter minutes receives that value for this invocation.
- The helper calculates 15 * 2 and returns 30.
- The caller assigns 30 to doubled and continues with its printing work.
Change planned to 20: predict doubled and the break-inclusive result. These examples use small minute values; multiplying arbitrary ints can overflow, and extracting the expression into a method does not remove that numeric limit.
Returning provides data; printing performs an output action
addMinutes returns 25 without producing console output. That is why The calculation returned. is the first printed line in this example. showMinutes receives the saved result and prints a message, but its void declaration says it provides no result value for the caller to use in an expression.
void does not mean the method does nothing. It may print, update state, or perform other actions; it simply has no returned value. Do not write int result = showMinutes(25). Conversely, a value-returning method need not print anything, and its result can be used more than once after the caller saves it.
Keep those responsibilities separate when possible. A calculation that only returns a number can support a console report, a later web interface, or a direct test without embedding one presentation choice. A method can technically both print and return, but that coupling should be deliberate rather than an accidental way to make a result visible.
Main.java · Returning is not printing
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
The calculation returned.
Minutes: 25
Reused result: 30
Every normally completing value path needs a result
labelFor chooses one label for a score that the caller has already validated to be between 0 and 100. A return immediately ends that method invocation. For score 85, the first branch returns its label, so the second condition and final return are not reached in that invocation.
For score 65, the first comparison is false and the second returns the foundation label. For score 40, neither condition succeeds, so the final return supplies Keep practising. This is a complete result decision. Deleting that final return leaves a path that reaches the method's end without a String, causing a compiler error.
A non-void method must not finish normally without producing its compatible result. A path that throws instead has different behavior, which later error-handling lessons cover. Do not fix a missing return by adding an arbitrary zero or empty string unless that value really belongs in the method's contract.
Main.java · Return one label from a complete decision
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Score 85: Advanced target met
Score 65: Foundation target met
Score 40: Keep practising
Try a useful missing-return diagnostic
Remove the final return from labelFor and run the example. A score below 50 could now reach the closing brace without a String result. Restore the meaningful final label, then test scores 49, 50, 79, and 80.
return leaves the current method, not every caller
showWelcome rejects a null or blank name before the welcome action. Because it returns void, its early exit is simply return; with no expression. That return leaves showWelcome, then main continues at Back in main. Returning from a helper is not the same as returning from main itself.
The second call has a nonblank value, so the helper strips surrounding whitespace and prints its welcome. A fresh call can follow a rejected call because the previous return ended only that invocation. The null check comes before isBlank so the short-circuit condition avoids calling a method on null.
A void method may also reach its closing brace without writing return at the end. Use an explicit early return when it makes an exceptional or rejected path clear. Printing an error alone does not stop the rest of the method; the return is what prevents an invalid name from reaching the welcome line.
Main.java · A helper return resumes its caller
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
A name is required.
Back in main.
Welcome, Mina!
Why does Back in main still print?
The blank-name return belongs to showWelcome, not main. The first helper call finishes, then main prints its next line and makes a second call. Replace the blank argument with null: the guard still handles it without preventing the second call.
Connect small methods through their results
The composition example first calculates remaining minutes, then asks another helper to describe that number. main keeps the sequence visible: calculate, classify, print. Each helper has one small responsibility, so changing the label does not require editing the remaining-minutes formula.
The remaining-minutes contract assumes both inputs are between 0 and 1440, a bounded daily-minute range. It floors an over-completed target at zero instead of reporting negative remaining work. Those are domain rules, not universal meanings of subtraction. Within that range the int subtraction is safe; arbitrary int inputs would require a different range policy.
A method contract states what inputs mean, which are permitted, and what the result means. The compiler checks types, not that a negative duration is sensible. A helper that assumes validated data needs that precondition stated, while a validation helper should clearly report acceptance or rejection rather than disguising invalid input as an ordinary result.
Main.java · Give one method's result to another
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Remaining: 20
Status: Keep practising
Each call has its own local working values
totalValues accepts a non-null int array and returns its sum as a long. It initializes its local total to zero each time it is called. The second call with an empty array therefore returns zero, not the previous call's total of 100. The local accumulator does not become a hidden shared result between calls.
This helper reads the array without assigning to its elements. The loop and accumulator stay inside the calculation; println remains in main. The explicit long accumulator also avoids overflowing an int sum when several large int elements are added. Negative values are allowed by this generic sum's stated contract, unlike the nonnegative minutes in the lab.
A local variable such as total cannot be used directly from main. Return the result main actually needs instead of exposing the helper's internal names. An array parameter still involves references, so a different helper could mutate elements; the next parameter-passing lesson explains that distinction. Merely extracting code into a method does not guarantee absence of side effects.
Main.java · Return a total without printing
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Total: 100
Empty total: 0
Try the same method with different data
Use 10, -5, and 2 in the generic sum: expect 7. Call it again with the same array and expect another 7, without extra printing from the helper. The lab below has a stricter domain: negative study minutes are rejected before its calculation methods run.
Choose the result type and the arithmetic deliberately
averageOf returns double, but that declaration alone does not force every intermediate operation to use floating-point arithmetic. If the method used (first + second) / 2 with int operands, 4 and 5 would produce integer 4 before that value was widened to 4.0 at return.
The example widens before the addition to prevent the sum of two int arguments from overflowing int, then divides by 2.0 for a fractional result. With 4 and 5 the returned value is 4.5. Casting only after integer division would not restore a fraction that had already been discarded.
A return expression must be compatible with the declared result type. An int expression can widen to double, but a String cannot serve as an int return value. Narrowing a double to int requires a deliberate conversion and policy; changing a method's declaration to silence a diagnostic can change its useful contract.
Main.java · The declared result type does not fix integer division
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Average: 4.5
Test the contract, not just whether the method compiles
A boolean result is useful when a helper answers a question. isValidScore returns true exactly for 0 through 100, inclusive. The sample calls test below, at, and above the boundaries. Those cases reveal mistakes such as excluding 0 or accepting 101 that a single middle value would never expose.
Write expected results before running. For a sum, include an empty array, a single value, and several values. For a remaining target, include under, exactly at, and over the target. Also test the method more than once to catch accidental state leakage or dependence on one particular caller.
Keep invalid-input behavior explicit. This validation method accepts any int and returns a boolean; totalValues instead requires a non-null array. Neither policy is automatically correct for every operation. The lab places validation in one helper and guards the calculation calls in main, so invalid inputs never masquerade as a legitimate zero-minute report.
Main.java · Test a boolean-returning boundary rule
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
-1 valid: false
0 valid: true
100 valid: true
101 valid: false
Repair exercise: return the result instead of losing it
The helper prints a total but always returns zero. main then reuses that zero and reports the wrong combined time. Make totalMinutes a calculation-only method that returns the actual total. Keep all output in main.
Main.java · Find the printed-but-lost result
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Reveal the explained repair
Printing Calculated: 60 does not send 60 back to the caller. The explicit return 0 is the value main receives. Return the accumulated total instead, and remove the helper's println so presentation stays in main. The caller can now reuse the same result in two messages. Empty input is a valid total of zero here, not a fallback for a missing or invalid array.
Main.java · Repaired calculation method
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Total: 60
Including break: 65
Independent lab: build reusable study-report methods
Refactor a study-session report into three reusable helpers. Keep reading and printing out of those helpers; main supplies the data, validates it, calls the calculations, and presents the results. Edit the array and target in source to test changes. This is a console teaching example, not saved study progress.
- Implement static boolean hasValidMinutes(int[] minutes): return false for null or any negative entry; return true for an empty array or nonnegative entries.
- Implement static long totalMinutes(int[] minutes): return the sum, using a long accumulator. Its precondition is a valid array. It must neither print nor mutate the array.
- Implement static int sessionsAtLeast(int[] minutes, int target): count entries greater than or equal to the target. Its preconditions are a valid array and a positive target. It must neither print nor mutate the array.
- In main, reject a nonpositive target with Target must be positive. and return. Then reject invalid minutes with Minutes must be present and nonnegative. and return before calling calculation helpers.
- For accepted data print Sessions:, Total minutes:, and Sessions meeting target:. Print Average minutes: with two decimal places using Locale.ROOT when nonempty, otherwise Average minutes: no sessions.
- Keep helper declarations inside Main but outside main. An empty array is valid: sum and target count are zero, and no average division occurs. Do not treat null as an empty array or leave output inside calculation methods.
The starter supplies sessions of 20, 35, 0, and 45 minutes, with a 30-minute target. No standard input is needed. Expected output:
Sessions: 4
Total minutes: 100
Sessions meeting target: 2
Average minutes: 25.00
Main.java · Build your reusable report methods
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Hints before the solution
Start with hasValidMinutes: guard null, scan for negatives, and return true only after the scan finishes. A valid empty scan returns true. In the sum and count helpers, initialize a fresh local accumulator, traverse the input, and return the final value after the loop.
In main, validate the target before the array. Store the two calculation results and print the report once. Check length before average division and cast total to double before dividing. Keep all helper declarations beside main, not nested inside it.
Reveal the explained lab solution
Main.java · Reusable report-methods solution
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
main handles validation order and output. hasValidMinutes answers one acceptance question, and the two calculation methods assume that stated precondition rather than inventing results for invalid data. An empty array passes validation but receives a no-average message. Each call has fresh local accumulators, and no helper assigns to any array element. Returning long from the sum avoids int overflow for the supplied int array values. The count includes a session exactly at the target because the comparison is >=. The helpers can be called from a test without producing console messages.
Test changes and boundaries
Edit the minutes array and target in the source. Reset restores the original program. Check that rejected input produces no normal report and that accepted calculations leave the source values unchanged.
- Use the supplied four sessions: total 100, two meeting the target, and average 25.00. Call the same helpers again and expect the same results without extra output.
- Replace the array with {}: expect zero sessions, sum 0, count 0, and Average minutes: no sessions. Do not divide by zero.
- Try null, then {20, -1, 45}. Each must produce only the invalid-minutes message. Try target 0 or -1 and expect only the target message, even if the array is invalid too.
- Try {29, 30, 31} with target 30. Exactly two sessions meet the inclusive boundary. Try {0} with target 1: the zero-minute session is valid but does not meet the target.
- Try {2147483647, 2147483647} with target 30. The returned total must be 4294967294, not an overflowed int. Verify the input elements remain unchanged.
Common mistakes and how to diagnose them
The caller gets zero even though the helper prints the right number
Inspect the return expression, not just the output. println does not supply a return value. Return the actual computed result and let the caller decide whether and how to display it.
missing return statement or incompatible types
Check every normally completing path and the declared result type. A value-returning method cannot simply reach its end. A void call cannot be assigned to a numeric variable, and a String expression cannot serve as an int result.
The helper declaration causes syntax errors inside main
Close main before declaring another ordinary method. Both methods belong directly inside the class braces. A method call belongs inside executable work; a method declaration defines that work elsewhere in the class.
non-static method cannot be referenced from a static context
The examples use static helpers so static main can call them directly. Keep that setup consistent. Instance methods require an appropriate object, a topic covered later; do not remove keywords randomly to hide the diagnostic.
The average returns 4.0 instead of 4.5
The int division may already have discarded the fractional part before conversion to double. Choose floating-point division in the expression itself and, when needed, widen before an addition that could overflow int.
A local accumulator cannot be read from main
A helper's local names belong to that invocation. Return a meaningful result and store it in the caller instead of reaching into internal variables. Also check that arguments match the helper's declared count and types.
Frequently asked questions
Does declaring a method run it?
No. In these examples main starts the work and calls helpers explicitly. A helper below main does not execute just because Java reaches that part of the source file.
Can a value-returning method be called without saving its result?
Yes, Java permits a method invocation statement that discards the returned result. That can be intentional, but discarding a calculation result may be a mistake if later work needs it. Save or use the result deliberately.
Is void the same as returning null?
No. void means no result value is provided. null is a reference value that a compatible reference-returning method can return; it cannot stand in for a primitive int result.
Does return in a helper stop main?
It ends that helper invocation and resumes the caller at the point after the call. A return from main ends main instead. Exceptions and other abrupt behavior have separate rules covered later.
Why not make every calculation print its answer?
A returned result can be reused, combined, tested, and displayed in different ways. Printing inside a calculation ties it to a particular output action and can cause unexpected extra messages when the helper is reused.
Let a method promise a result you can actually use
A declaration defines work; a call requests it. Parameters name inputs, and arguments supply them. A returned value resumes the caller's expression, while printing is a separate action. Keep complete result paths, local working values, and input contracts clear.
Before moving on, explain why printing a correct sum cannot repair return 0, why a helper return does not stop main, and why an empty valid array differs from missing minutes. Next: method parameters and pass-by-value.
Can you trace the call and the value that comes back?
Answer all six questions and read the explanations. Results are temporary on this page and do not save course progress.
References and related learning
The scenarios, explanations, examples, and exercises are original SovranCode material. Official references support the Java 21 language rules.
Review array summaries · Review complete decisions · Review result types · Java course roadmap.
Last updated: