06 Functions
January 8, 2024 · 5 min read
If you have any questions, feel free to comment below. Click the block can copy the code.
And if you think it's helpful to you, just click on the ads which can support this site. Thanks!
Function Basics #
A typical function definition includes the following parts: modifiers, return type, function name, a list of zero or more parameters, and the function body.
Writing a Function #
Let’s write a program to calculate a factorial. The program is as follows:
public class Main {
private static int fact(int val) {
int res = 1;
for (int i = 1; i <= val; i ++ )
res *= i;
return res;
}
public static void main(String[] args) {
int res = fact(5);
System.out.printf("5! is %d\n", res);
}
}
The function is named fact; it takes an integer argument and returns an integer value. The return statement ends fact and returns the value of res.
Modifiers include private and static; these are concepts related to classes.
Parameters and Arguments #
Arguments provide the initial values of parameters. The first argument initializes the first parameter, the second argument initializes the second parameter, and so on. The types and number of parameters and arguments must match.
fact("hello"); // Error: incorrect argument type
fact(); // Error: too few arguments
fact(42, 10, 0); // Error: too many arguments
fact(' '); // Correct: this argument is automatically converted to int; the ASCII value of ' ' is 32, so this is equivalent to fact(32);
Function Parameter Lists #
A function’s parameter list can be empty, but it cannot be omitted. Parameters in the list are usually separated by commas, and each parameter is a declaration with a declarator. Even if two parameters have the same type, both types must be written:
int f3(int v1, v2) {/* … */} // Incorrect
int f4(int v1, int v2) {/* … */} // Correct
Function Return Types #
Most types can be used as a function’s return type. One special return type is void, which indicates that the function returns no value. A function can also return an array, string, or other object:
import java.util.Arrays;
public class Main {
private static int[] newArray() {
int[] a = {1, 2, 3};
return a;
}
private static String newString() {
return "Hello World";
}
public static void main(String[] args) {
int[] x = newArray();
System.out.println(Arrays.toString(newArray()));
System.out.println(newString());
}
}
Variable Scope #
This chapter uses only static member variables and static member functions.
- Variables defined inside a function are local variables and can only be used within that function.
- Variables defined in a class are member variables and can be accessed by all member functions of the class.
When a local variable and a global variable have the same name, the local variable takes precedence.
public class Main {
private static int x = 4;
private static void f1() {
int x = 3;
System.out.println(x);
}
private static void f2() {
System.out.println(x);
}
private static void f3() {
System.out.println(x + 1);
}
public static void main(String[] args) {
f1();
f2();
f3();
}
}
Passing Arguments #
Passing by Value #
The eight primitive data types, their wrapper types, and types such as String are passed by value.
The initial value of an argument is copied to a parameter. Changes to the parameter do not affect the argument’s initial value.
public class Main {
private static void f(int x) {
x = 5;
}
public static void main(String[] args) {
int x = 10;
f(x);
System.out.println(x);
}
}
Here, the addresses of the objects a and b are passed in. In swap, the addresses held by a and b are exchanged, but this does not change the values of the original objects’ references. Integer is an immutable object; assigning or modifying it actually creates a new object.
import java.util.Arrays;
public class Main {
private static void swap(Integer a, Integer b) {
Integer t = a;
a = b;
b = t;
System.out.printf("%d %d\n", a, b); // 4 3
}
public static void main(String[] args) {
Integer a = 3, b = 4;
swap(a, b);
System.out.printf("%d %d\n", a, b); // 3 4
}
}
Passing References #
Objects of types other than String, such as arrays and StringBuilder, use reference passing.
Pass the argument’s reference (address) to the parameter, use that reference to locate the variable’s actual address, and modify the value at that address. Thus, modifying the parameter affects the argument’s initial value.
import java.util.Arrays;
public class Main {
private static void f1(int[] a) {
for (int i = 0, j = a.length - 1; i < j; i ++, j -- ) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
private static void f2(StringBuilder sb) {
sb.append("Hello World");
}
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
f1(a); // 5 4 3 2 1
System.out.println(Arrays.toString(a));
StringBuilder sb = new StringBuilder("");
f2(sb); // Hello World
System.out.println(sb);
}
}
Return Types and return Statements
#
A return statement terminates the currently executing function and returns control to the point where the function was called.
Functions Without Return Values #
A return statement without a value can only be used in functions whose return type is void. Functions returning void do not require a return statement because return is implicitly executed after the last statement in such functions.
Usually, a void function can use return to exit early. This use of return is somewhat like using break to exit a loop.
Functions With Return Values #
If a function’s return type is not void, every branch of the function must have a return statement, and each return statement must return a value. The type of the returned value must be the same as the function’s return type or be implicitly convertible to it.
Function Overloading #
Function overloading means that multiple functions in the same class have the same name but different parameter lists. The compiler chooses the best-matching function based on the types of the arguments.
import java.util.Scanner;
public class Main {
private static int max(int a, int b) {
System.out.println("int max");
if (a > b) return a;
return b;
}
private static double max(double a, double b) {
System.out.println("double max");
if (a > b) return a;
return b;
}
public static void main(String[] args) {
System.out.println(max(3, 4));
System.out.println(max(3.0, 4.0));
}
}
Recursion #
A function can also call itself from within its body.
import java.util.Scanner;
public class Main {
private static int fib(int n) { // Find the nth term of the Fibonacci sequence
if (n <= 2) return 1;
return fib(n - 1) + fib(n - 2);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
System.out.println(fib(n));
}
}
A few tips:
2. Code executes on a single thread, one line at a time.
3. String is special because its value is not modified. If you modify the value of a String, a new area of memory is allocated to store the new value; the original value remains unchanged.
4. Passing a reference is essentially passing by value, except that the value passed is an address.
5. Java does not have the concept of pointers.
Related readings
- 05 Strings
- 04 Arrays
- 03 Loops
- 02 Conditional Statements
- 01 Variables, Operators, Expressions, Input and Output
If you want to follow my updates, or have a coffee chat with me, feel free to connect with me: