Defining Functions in Jshell
A function definition has the following parts:
- If the function returns a value, then it should begin with a return type,
which tells us what type of value it returns. If a function doesn't return a
value, then it should begin with the keyword
void
. - The function has a name after the return type. Function names follow the standard rules for Java identifiers that we learned for variable names.
- If the function has any parameters, then these are listed in parenthesis after the function name. If the function has no parameters, then we must still include a set of empty parenthesis after the name.
- The function's body (the code it will execute) goes inside a code block after the parameter list.
<return type> <function name>(<parameter list>) {
<function body>
}
A function's parameters tell the program what information the function needs to
receive from the code that calls it. A parameter acts like a variable, but its
initial value is supplied when we call it. The parameter list just looks like a
comma-separated list of variable declarations. For example, if a function needed
two parameters, a double and a boolean, then its parameter list might look like
this: functionName(double x, boolean y)
. Like variable names, function and
parameter names should be descriptive whenever possible. I've used generic names
here because we have no further context for what these parameters mean. If they
referred to a distance and whether that distance was in metric units, then we
might instead write functionName(double distance, boolean isMetric)
.
Return Values
If a function is meant to create information for another part of the program to
use, then it should return that information to the code that called it. You
have already used functions with return values: all of the input functions (
nextLine
, nextInt
, etc.) return the value they read from the user, and all
of the Math
functions (abs
, min
, sqrt
, etc.) return the number they
calculated.
If we want our function to return a value, then we need to include the value's
type before the name. We also need to give our function a return statement
that includes the value it returns. A return statement is the return
keyword
followed by an expression whose type matches the function's return type. For
example, if we had a function that adds two double
values, then its return
statement might look like this: return x + y;
, where x
and y
are the
function's parameters. The entire function would look like this:
double add(double x, double y) {
return x + y;
}
This isn't a useful function because it's easier to add by writing 2 + 3
than
by calling our function with add(2, 3)
. This is just a short function that
demonstrates what a return statement looks like.
If our function has a return type, then it must always return a value of that
type. It should not be possible for such a function to end without returning.
For example, take a look at the following divide
function:
int divide(int x, int y) {
if (y != 0) {
return x / y;
}
}
This is not a valid function because when y
is equal to 0
, the function does
not return a value. It must either always return a value or never return a
value. There are exceptions (and they're literally called exceptions), but
for now all of our functions must return something if they have a return type.
We don't have a good way to handle errors yet, so the best we can do for now is
let our divide
function attempt the division and crash if it divides by zero:
int divide(int x, int y) {
return x / y;
}
When new programmers are using if statements or loops in a function and have multiple return statements, it's common to accidentally write functions like the first version of divide that aren't guaranteed to return a value. A few tips for avoiding this:
- If your return statement is inside an if statement, make sure that if
statement has an
else
clause with its own return statement. - If you have an else-if chain with return statements inside the bodies of the
ifs/else-ifs, then make sure the chain ends with an
else
and that thiselse
contains a return statement. - If you have a return statement inside of a loop, then you should probably have a default return statement at the end of the function body in case the loop is never executed or the return statement inside the loop is never triggered.
Finally, note that as soon as a function reaches a return statement, the function will stop executing. If you put code after a return statement, it will never execute:
int divide(int x, int y) {
return x / y;
println("This will never be printed!");
}
Practice
Here are a few descriptions of small functions we could write. Try writing a few of them yourself before looking at the solutions.
Before you write a function definition, it may help to answer two questions:
- Does this function require any parameters? If it always does the same thing, or it doesn't rely on input from other parts of the program, then it probably doesn't need parameters.
- Does this function return anything? If another part of the program would want to use a value created by the function, then it should return that value. Printing a value is not the same as returning it, and if the function's only job is to print something then it probably doesn't return a value.
The function descriptions:
- A function named
sayHello
that prints the message "Hello, World!". - A function named
greetPerson
that takes a name and prints a greeting in the form of "Hello <name>, how are you doing today?". - A function named
square
that calculates (but does not print) the square of an integer.
Solution code:
void sayHello() {
println("Hello, World!");
}
void greetPerson(String name) {
println("Hello " + name + ", how are you doing today?");
}
int square(int x) {
return x * x;
}
Solution explanations:
- The
sayHello
function does not require any parameter input because it always does the same thing. No part of the function's behavior needs to change, and it doesn't need additional information to print "Hello, World!". The function is printing rather than producing information for another part of the program, so it also doesn't need to return anything. This is why its return type isvoid
. - The
greetPerson
function is supposed to greet someone by name, but the description does not say what name we're supposed to use. Instead, it's supposed to take any name and insert it into a message, which means it needs us to tell it what name to print. This is why we have aname
parameter. As with thesayHello
function, we're not producing information to use in other parts of the program, we're sending information outside of the program withprintln
. This means we don't need to return anything, and our return type isvoid
. - The
square
function needs to know what number it's squaring, and the number is supposed to be anint
according to the description, so we need a single parameter with the typeint
. This parameter doesn't mean anything beyond the fact that it's a number, so an arbitrary name likex
ora
is fine here. The function is supposed to calculate something, not print it, so in order for this to be useful we'll have to return the resulting value so another part of the program can make use of it. The calculation produces anint
, so our return type should beint
.