Skip to content

Introduction to Java

Part 2 · Programming languages · Chapter 8 · Lecture notes, volume 2 (PDF) · Exercises: Introduction to Java

Introduction

In the chapters «Introduction to C++» and «Introduction to Python» we translated the pseudo-code of our algorithms into a compiled and into an interpreted programming language. In this chapter we introduce a third programming language, Java, which is in between: its programs are compiled into an intermediate code, which is then executed by a virtual machine. Its syntax is very close to the syntax of C++, but every program is organized into classes.

The chapter follows the same path as the two previous chapters, so that the three languages can be compared section by section:

  • the main characteristics of the language and the structure of a program;

  • variables, data types, input and output;

  • operators, conditional statements and loops;

  • arrays, and the dynamic lists of the class ArrayList;

  • methods (the Java name for functions), their parameters and their return values;

  • a complete algorithm, the search of the maximum value in an array, written in pseudo-code and in Java;

  • the bitwise operators and a summary table that compares Java with C++ and Python.

Every fragment of code of the chapter has been compiled with the javac compiler and executed with the java virtual machine (OpenJDK 25): the outputs reported in the examples are the ones printed by the programs.

In pseudo-code the entries of an array \(a[1..n]\) are indexed from \(1\) to \(n\); in Java, as in C++ and Python, the elements of an array of size \(n\) are indexed from \(0\) to \(n-1\). The entry \(a[i]\) of the pseudo-code corresponds to the element a[i-1] of the Java code.

8.1 Main characteristics of the programming language

The main characteristics of Java are the following.

  • Java is a compiled and interpreted language: the source code (.java files) is first compiled into bytecode (.class files) by the Java compiler javac, and then the bytecode is executed by the Java Virtual Machine (JVM). This makes Java programs platform-independent: the same bytecode runs on any machine that has a JVM installed (“write once, run anywhere”).

  • Java is a strongly and statically typed language: every variable must be declared with its data type before use, and its data type cannot change during the execution.

  • Java is object-oriented: every program is organized into classes. The entry point of every Java program is the main method of a class.

  • Java supports methods (the Java term for functions), enabling a modular and reusable approach to programming.

  • As in C++, the block structure of the code is defined by curly braces {}, and each instruction must end with the reserved symbol “;”.

  • As in C++, a single-line comment starts with the reserved symbol “//”, and multi-line comments are enclosed between the reserved symbols “/*” and “*/”.

Example 8.1: comments in Java

This is an example of a single-line comment:

// This is a comment line

This is an example of a multi-line comment:

/* This is a
   multi-line comment */

8.1.1 The structure of a program

Before describing the single instructions, we look at the skeleton that every program shares. A Java program is made of one or more classes; the execution starts from the method public static void main(String[] args) of the class that is launched.

Example 8.2: the skeleton of a program

public class HelloWorld {

    public static void main(String[] args) {
        // The instructions of the program are written here
        System.out.println("Hello, world!");
    }
}

A class declared public must be saved in a file with the same name as the class: here HelloWorld.java. The program is compiled and executed with the commands

javac HelloWorld.java
java HelloWorld

The first command produces the bytecode file HelloWorld.class; the second one executes it (note that the extension is not written). The output is

Hello, world!

In the following examples we write only the instructions that matter: unless they contain a complete program, the fragments of code are meant to be placed inside the curly braces of main.

Every Java instruction belongs to a method, and every method belongs to a class. Each instruction ends with “;”.

8.2 Variables and data types

The source code operates on variables, and every variable has a data type.

  • The four fundamental data types of Java are:

    1. The data type “int” represents an integer stored with \(32\) bits: a whole number from \(-2^{31} = -2147483648\) to \(2^{31}-1 = 2147483647\). For larger integers the data type long (\(64\) bits) is used.

    2. The data type “boolean” represents a Boolean value: true or false (lowercase).

    3. The data type “double” represents a floating-point number with double precision (\(64\) bits), as in C++. The data type float has single precision, and its values are written with the suffix f (e.g., 3.14f).

    4. The data type “char” represents a single character, enclosed in single quotes (e.g., 'A', '7').

  • The data type “String” (with capital S) represents a sequence of characters enclosed in double quotes, and it is the standard way to handle text in Java.

  • A variable acts as a container that stores a value of a specific data type for later use.

  • Variables are assigned values using the assignment operator “=”. When a new value is assigned, the previous value is overwritten.

  • The compiler checks the data types: assigning a value of a wrong type (for example the string "five" to a variable of type int) or using a variable that has not received a value is a compilation error, and the program is not produced.

Variables must be declared with their data type before use, as in C++.

Example 8.3: variable declarations and assignments

int age = 25;              // Integer variable
boolean isRaining = false; // Boolean variable
double pi = 3.14159;       // Double-precision floating-point
float small = 3.14f;       // Single-precision floating-point
double large = 123456.789; // Double-precision floating-point
char letter = 'A';         // Character variable
String name = "Alice";     // String variable

age = 26; // The previous value 25 is overwritten
System.out.println(age + " " + isRaining + " " + pi + " " + small);
System.out.println(large + " " + letter + " " + name);

Output:

26 false 3.14159 3.14
123456.789 A Alice

Unlike C++, the Boolean value is displayed as false and the number 123456.789 is displayed with all its digits.

Example 8.4: the limits of the data type int

int big = Integer.MAX_VALUE;  // The largest int
System.out.println(big);
System.out.println(big + 1);  // Overflow: the result does not fit in 32 bits

long bigger = (long) big + 1; // Computed with 64 bits
System.out.println(bigger);

Output:

2147483647
-2147483648
2147483648

When the result of an operation between int values does not fit in \(32\) bits, it “wraps around” to the other end of the interval, without any error message. The integers of Python never overflow.

8.3 Input and output

  • The object System.out (the standard output, provided by the class System) has the methods that display values on the screen. The most common are:

    • System.out.println(): prints a value followed by a new line;

    • System.out.print(): prints a value without the new line.

  • Values and strings are concatenated with the + operator inside a print statement: when one of the two operands of + is a String, the other one is converted into text. The expression is evaluated from left to right, so an arithmetic operation inside a concatenation must be enclosed in parentheses.

  • The method System.out.printf() prints a formatted text: in the first string, %d is replaced by an integer, %s by a string, %.kf by a floating-point number with exactly \(k\) digits after the decimal point, and %n by a new line.

Example 8.5: screen output

int n = 42;
System.out.println("The value of the variable is " + n);
System.out.println("n = " + n + ", doubled = " + (n * 2));

System.out.println("n + 1 = " + n + 1);   // Concatenation: "42" then "1"
System.out.println("n + 1 = " + (n + 1)); // Addition, then concatenation

System.out.print("No new line ");
System.out.println("after print");
System.out.printf("%d divided by %d is %.2f%n", 10, 3, 10.0 / 3);

Output:

The value of the variable is 42
n = 42, doubled = 84
n + 1 = 421
n + 1 = 43
No new line after print
10 divided by 3 is 3.33
  • The decimal separator printed by printf depends on the language settings of the computer: on a computer set to Italian the last line is 10 divided by 3 is 3,33, with a comma. The method println always uses the point.

  • To read input from the keyboard, the class Scanner of the package java.util is used. It must be imported with the instruction import java.util.Scanner;, written at the beginning of the file, before the class. The methods nextLine(), nextInt() and nextDouble() read a line of text, an integer and a floating-point number.

Example 8.6: keyboard input with Scanner

import java.util.Scanner;

public class InputExample {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("Enter your name: ");
        String name = sc.nextLine();     // Reads a String

        System.out.print("Enter an integer: ");
        int n = sc.nextInt();            // Reads an int

        System.out.print("Enter a real number: ");
        double x = sc.nextDouble();      // Reads a double

        System.out.println("Hello " + name + ", n = " + n + ", x = " + x);
        sc.close();
    }
}

Example of execution (the user types Ada, 7 and 2.5):

Enter your name: Ada
Enter an integer: 7
Enter a real number: 2.5
Hello Ada, n = 7, x = 2.5

Like printf, the method nextDouble() follows the language settings: on a computer set to Italian the real number must be typed as 2,5.

8.4 Operators

Operators are symbols that perform operations on variables and values. The operators of Java are the same as those of C++: arithmetic, assignment, increment and decrement, relational and logical operators.

8.4.1 Arithmetic operators

Arithmetic operators, used to perform basic mathematical operations:

  • + (Addition) \(\rightsquigarrow\) Adds two values.

  • - (Subtraction) \(\rightsquigarrow\) Subtracts one value from another.

  • * (Multiplication) \(\rightsquigarrow\) Multiplies two values.

  • / (Division) \(\rightsquigarrow\) Divides one value by another. Integer division when both operands are integers.

  • % (Modulus) \(\rightsquigarrow\) Returns the remainder of a division.

Example 8.7: arithmetic operators

int a = 10, b = 3;

System.out.println("Addition:       " + (a + b));
System.out.println("Subtraction:    " + (a - b));
System.out.println("Multiplication: " + (a * b));
System.out.println("Division:       " + (a / b));  // Integer division
System.out.println("Modulus:        " + (a % b));  // Remainder of division
System.out.println("Real division:  " + ((double) a / b));

Output:

Addition:       13
Subtraction:    7
Multiplication: 30
Division:       3
Modulus:        1
Real division:  3.3333333333333335
  • As in C++, the division operator / performs integer division when both operands are integers, and the quotient is truncated toward zero: 10 / 3 is 3 and -7 / 2 is -3 (with remainder -7 % 2 equal to -1). To obtain a floating-point result, at least one operand must be of type double, for example with the type conversion (cast) (double) a / b.

  • The conversion (int) removes the decimal part of a double: (int) 3.9 is 3. There is no operator for the power: the method Math.pow(x, y) returns \(x^y\) as a double.

Example 8.8: integer and floating-point division

int a = 10, b = 3;

System.out.println(a / b);             // Integer division
System.out.println(10.0 / 3);          // Floating-point division
System.out.println((double) a / b);    // Conversion of a to double
System.out.printf("%.2f%n", (double) a / b); // Two decimals
System.out.println(-7 / 2 + " " + -7 % 2);   // Truncation toward zero
System.out.println((int) 3.9 + " " + Math.pow(2, 10));

Output:

3
3.3333333333333335
3.3333333333333335
3.33
-3 -1
3 1024.0

8.4.2 Assignment operators

Assignment operators, used to assign values to variables:

  • = (Assignment) \(\rightsquigarrow\) Assigns a value to a variable.

  • += (Addition assignment) \(\rightsquigarrow\) Adds a value and assigns the result.

  • -= (Subtraction assignment) \(\rightsquigarrow\) Subtracts a value and assigns the result.

  • *= (Multiplication assignment) \(\rightsquigarrow\) Multiplies and assigns the result.

  • /= (Division assignment) \(\rightsquigarrow\) Divides and assigns the result.

  • %= (Modulus assignment) \(\rightsquigarrow\) Applies the modulus and assigns the result.

Example 8.9: assignment operators

int x = 10;  // Assignment
System.out.println("Initial value: " + x);

x += 5;  System.out.println("After += 5: " + x); // x = x + 5
x -= 3;  System.out.println("After -= 3: " + x); // x = x - 3
x *= 2;  System.out.println("After *= 2: " + x); // x = x * 2
x /= 4;  System.out.println("After /= 4: " + x); // x = x / 4
x %= 4;  System.out.println("After %= 4: " + x); // x = x % 4

Output:

Initial value: 10
After += 5: 15
After -= 3: 12
After *= 2: 24
After /= 4: 6
After %= 4: 2

Two instructions can be written on the same line, since each of them ends with “;”.

8.4.3 Increment and decrement operators

Increment and decrement operators:

  • ++ (Increment) \(\rightsquigarrow\) Increases the value of a variable by 1.

  • - - (Decrement) \(\rightsquigarrow\) Decreases the value of a variable by 1.

  • As in C++, the pre-increment (++x) increments the value before returning it, and the post-increment (x++) returns the value first, then increments it. The same logic applies to the decrement operator (- -x and x- -).

Example 8.10: increment and decrement operators

int x = 5;
System.out.println("Initial value: " + x);
System.out.println("Pre-increment (++x): " + ++x);
System.out.println("Post-increment (x++): " + x++);
System.out.println("Value after post-increment: " + x);
System.out.println("Pre-decrement (--x): " + --x);
System.out.println("Post-decrement (x--): " + x--);
System.out.println("Value after post-decrement: " + x);

Output:

Initial value: 5
Pre-increment (++x): 6
Post-increment (x++): 6
Value after post-increment: 7
Pre-decrement (--x): 6
Post-decrement (x--): 6
Value after post-decrement: 5

8.4.4 Relational operators

Relational operators, used to compare values and return a boolean result:

  • == (Equal to) \(\rightsquigarrow\) Checks if two values are equal.

  • != (Not equal to) \(\rightsquigarrow\) Checks if two values are different.

  • < (Less than) \(\rightsquigarrow\) Checks if one value is smaller than another.

  • > (Greater than) \(\rightsquigarrow\) Checks if one value is larger than another.

  • <= (Less than or equal to) \(\rightsquigarrow\) Checks if one value is smaller than or equal to another.

  • >= (Greater than or equal to) \(\rightsquigarrow\) Checks if one value is larger than or equal to another.

  • Relational operators return a value of type boolean, displayed as true or false (not as 1 and 0 as in C++). These operators are commonly used in conditional statements and loops.

  • The operator == compares the values of the primitive data types (int, double, char, boolean); two String values are compared with the method equals, for example name.equals("Alice").

Example 8.11: relational operators

int a = 10, b = 5;

System.out.println("a == b: " + (a == b)); // Equal to
System.out.println("a != b: " + (a != b)); // Not equal to
System.out.println("a < b: " + (a < b));   // Less than
System.out.println("a > b: " + (a > b));   // Greater than
System.out.println("a <= b: " + (a <= b)); // Less than or equal to
System.out.println("a >= b: " + (a >= b)); // Greater than or equal to

Output:

a == b: false
a != b: true
a < b: false
a > b: true
a <= b: false
a >= b: true

8.4.5 Logical operators

Logical operators, used for logical operations, often in conditional statements:

  • && (Logical AND) \(\rightsquigarrow\) Returns true if both conditions are true.

  • || (Logical OR) \(\rightsquigarrow\) Returns true if at least one condition is true.

  • ! (Logical NOT) \(\rightsquigarrow\) Reverses the Boolean value.

Example 8.12: logical operators

boolean c1 = true, c2 = false;

System.out.println("c1: " + c1);
System.out.println("c2: " + c2);
System.out.println("c1 && c2: " + (c1 && c2)); // True only if both are true
System.out.println("c1 || c2: " + (c1 || c2)); // True if at least one is true
System.out.println("!c1: " + (!c1));           // Reverses the value
System.out.println("!c2: " + (!c2));

Output:

c1: true
c2: false
c1 && c2: false
c1 || c2: true
!c1: false
!c2: true

8.5 Conditional statements

The relational and logical operators produce the conditions that decide which instructions are executed.

  • The if statement evaluates a condition inside parentheses (). If the condition is true, the block inside the curly braces {} is executed. The optional else if clause checks additional conditions, and the optional else clause handles all the remaining cases.

  • Unlike C++, the condition must be of type boolean: an integer is not accepted as a condition, so if (n % 2) is a compilation error and the test must be written if (n % 2 != 0).

Example 8.13: conditional statement

int number = 10;

// Check if number is positive
if (number > 0) {
    System.out.println("The number is positive.");
} else {
    System.out.println("The number is non-positive.");
}

Output:

The number is positive.

Example 8.14: if / else if / else

int score = 85;
String grade;

if      (score >= 90) { grade = "A"; }
else if (score >= 80) { grade = "B"; }
else if (score >= 70) { grade = "C"; }
else if (score >= 60) { grade = "D"; }
else                  { grade = "F"; }

System.out.println("Score: " + score + ", Grade: " + grade);

Output:

Score: 85, Grade: B

The conditions are evaluated from top to bottom, and only the block of the first true condition is executed. The variable grade is declared without a value: the compiler accepts it because every branch assigns a value to it before it is printed.

8.5.1 Ternary operator (conditional operator)

  • The ternary operator ?: is the same as in C++. Syntax: condition ? value_if_true : value_if_false.

Example 8.15: ternary operator

int number = 10;

// condition ? value_if_true : value_if_false
String result = (number > 0) ? "positive" : "non-positive";
System.out.println("The number is " + result);

// Finding the maximum of two numbers
int a = 15, b = 20;
int maximum = (a > b) ? a : b;
System.out.println("Maximum: " + maximum);

// Checking even or odd
int n = 7;
String parity = (n % 2 == 0) ? "even" : "odd";
System.out.println(n + " is " + parity);

// Absolute value
int x = -5;
int absValue = (x >= 0) ? x : -x;
System.out.println("Absolute value of " + x + " is " + absValue);

Output:

The number is positive
Maximum: 20
7 is odd
Absolute value of -5 is 5

The class Math also provides the methods Math.max(a, b) and Math.abs(x), which return the same values.

8.6 Loops

Conditional statements choose whether a block of code is executed; loops decide how many times it is executed.

  • Loops are used to execute a block of code repeatedly while a condition is met. As in C++, the most commonly used loops of Java are the while loop and the for loop.

8.6.1 The while loop

  • The while loop executes a block of code as long as the condition inside the parentheses () evaluates to true. When the condition is false, the loop terminates.

Example 8.16: while loop

int i = 1; // Initialization

while (i <= 5) { // Condition
    System.out.println("Number: " + i);
    i++; // Increment
}

Output:

Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

8.6.2 The for loop

  • The for loop combines initialization, condition, and increment (or decrement) in one statement, exactly as in C++.

Example 8.17: for loop

// Initialization; Condition; Increment
for (int i = 1; i <= 5; i++) {
    System.out.println("Number: " + i);
}

The output is the same as in the while loop of Example 8.16.

8.6.3 The break and continue statements

  • The break statement immediately terminates the loop.

  • The continue statement skips the rest of the current iteration and moves to the next one.

Example 8.18: break and continue

for (int i = 1; i <= 10; i++) {
    if (i % 2 == 0) {
        continue; // Skip the even numbers
    }
    if (i > 7) {
        break; // Stop the loop at the first odd number greater than 7
    }
    System.out.print(i + " ");
}
System.out.println();

Output:

1 3 5 7

The output is the same as in the C++ and Python versions: the value 9 triggers the break.

8.7 Arrays

Loops become really useful when they visit collections of values. A collection of variables of the same data type is stored in an array.

  • An array in Java is an ordered collection of elements of the same data type, with a size fixed at creation time: the size cannot change afterwards.

  • The data type of an array of integers is written int[]. An array is allocated with the new operator, for example new int[n], where the size n can be decided during the execution, as for the dynamic-size arrays of C++. The elements of a new array are initialized to 0 (to false for boolean).

  • Elements are accessed using their index inside square brackets [], starting from 0: the elements of an array of size \(n\) are a[0], a[1], …, a[n-1]. Every array knows its size: the length of an array a is a.length.

  • Unlike C++, the memory of an array must not be freed with delete[]: it is released automatically by the garbage collector of the JVM when the array is no longer used.

Arrays are allocated with new before use (or created with a list of values in curly braces). Indices start at 0, the size is fixed and is given by a.length.

Example 8.19: creating and accessing an array

int n = 5;

int[] a = new int[n]; // Allocation of an array of n integers

for (int i = 0; i < n; i++) {
    a[i] = i * 2; // Example of value assignment
}

System.out.println("Length: " + a.length);
System.out.println("a[0] = " + a[0]); // First element
System.out.println("a[4] = " + a[4]); // Last element, index n-1

Output:

Length: 5
a[0] = 0
a[4] = 8

Accessing an index that does not exist, for example a[5], stops the program with the error ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5 (in C++ the same access is not checked).

  • An array whose values are known when the program is written can be created by listing its values inside curly braces, as in C++.

  • The enhanced for loop for (int x : a) visits the elements of the array a directly, without using their indices, like the for loop over a list of Python.

  • The method Arrays.toString(a), of the class Arrays of the package java.util, returns the elements of an array as a text in square brackets.

Example 8.20: array literal and iteration

import java.util.Arrays;

int[] a = {9, 12, 3, 16, 19, 11, 12};
int n = a.length;

for (int i = 0; i < n; i++) {      // Loop over the indices
    System.out.println("a[" + i + "] = " + a[i]);
}

for (int x : a) {                  // Loop over the elements
    System.out.print(x + " ");
}
System.out.println();

System.out.println(Arrays.toString(a));

Output:

a[0] = 9
a[1] = 12
a[2] = 3
a[3] = 16
a[4] = 19
a[5] = 11
a[6] = 12
9 12 3 16 19 11 12
[9, 12, 3, 16, 19, 11, 12]

The import instruction is written at the beginning of the file, before the class.

8.7.1 Two-dimensional arrays

  • Two-dimensional arrays (matrices) are declared with two pairs of square brackets [][], and allocated with new int[m][n] (\(m\) rows and \(n\) columns) in a single instruction. The element in row \(i\) and column \(j\) is accessed as matrix[i][j], with both indices starting from \(0\); matrix.length is the number of rows and matrix[i].length is the number of columns of row \(i\).

  • A two-dimensional array can also be created by listing its values row by row: int[][] c = {{3, 1, 4}, {1, 5, 9}}; creates an array with \(2\) rows and \(3\) columns, and c[1][2] is the element in the second row and third column, equal to \(9\).

Example 8.21: two-dimensional array (matrix)

int m = 3; // Number of rows
int n = 2; // Number of columns

int[][] matrix = new int[m][n]; // Allocation of an m x n matrix

for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        matrix[i][j] = i * j; // Example of value assignment
    }
}

for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        System.out.println("matrix[" + i + "][" + j + "] = " + matrix[i][j]);
    }
}

Output:

matrix[0][0] = 0
matrix[0][1] = 0
matrix[1][0] = 0
matrix[1][1] = 1
matrix[2][0] = 0
matrix[2][1] = 2

8.7.2 Lists of variable size: ArrayList

  • When the number of elements is not known in advance, the class ArrayList of the package java.util provides a list that grows during the execution, like the lists of Python. The data type of a list of integers is ArrayList<Integer>: the elements of an ArrayList are objects, and Integer is the class that corresponds to int.

  • The method add(x) appends the element x at the end of the list, get(i) returns the element of index \(i\), set(i, x) replaces it, and size() returns the number of elements.

Example 8.22: a list of variable size

import java.util.ArrayList;

ArrayList<Integer> list = new ArrayList<>(); // Empty list

for (int i = 1; i <= 4; i++) {
    list.add(i * i);  // The list grows
}
list.set(0, 100);     // Replaces the element of index 0

System.out.println(list + " has " + list.size() + " elements");
System.out.println("list.get(2) = " + list.get(2));

Output:

[100, 4, 9, 16] has 4 elements
list.get(2) = 9

8.8 Methods (functions)

As in pseudo-code, an algorithm is written as a function that receives the input and returns the output. In Java, functions are called methods and must always be defined inside a class.

  • A method in Java consists of:

    1. an optional access modifier (e.g., public, private) and the keyword static when the method belongs to the class rather than to an object of the class (all the methods of this chapter are static);

    2. a return type: specifies the type of the returned value (void if nothing is returned);

    3. a method name: the unique identifier of the method;

    4. a parameter list (optional): specifies the input values, each one with its data type;

    5. a body: the block of code executed when the method is called;

    6. a return statement, mandatory if the return type is not void.

  • The entry point of every Java program is the method public static void main(String[] args), which plays the role of the main function of C++. The parameter args contains the words written after the name of the class in the command java.

  • Unlike C++, a method can be called before the point where it is defined in the class: the order of the methods inside a class does not matter.

  • Java source code can also be compiled and executed online, for example at the following address:
    www.mycompiler.io/online-java-compiler

Example 8.23: methods

public class Main {

    // Method definition
    static int addition(int a, int b) {
        return a + b; // Returns the sum
    }

    // Method definition
    static int multiplication(int a, int b) {
        return a * b; // Returns the product
    }

    public static void main(String[] args) {
        int sum = addition(5, 10);         // Method call
        System.out.println("Sum: " + sum);

        int prod = multiplication(5, 10);  // Method call
        System.out.println("Prod: " + prod);
    }
}

Output:

Sum: 15
Prod: 50

Example 8.24: method operating on a two-dimensional array

public class Main {

    static int sumMatrix(int[][] matrix, int rows, int cols) {
        int sum = 0;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                sum += matrix[i][j];
            }
        }
        return sum;
    }

    public static void main(String[] args) {
        int m = 3, n = 2;
        int[][] matrix = new int[m][n];

        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
                matrix[i][j] = i * j;

        int total = sumMatrix(matrix, m, n);
        System.out.println("Sum of matrix elements: " + total);
    }
}

Output:

Sum of matrix elements: 3

The body of a for loop made of a single instruction can be written without curly braces, as in C++.

8.8.1 Parameters and return values

  • In Java every parameter is passed by value: the method receives a copy of the argument. For the primitive data types (int, double, boolean, char) the changes made to the copy do not affect the variable of the caller; there is no passing by reference as with the symbol & of C++.

  • A variable of type int[] does not contain the elements, but a reference to the array (similar to the pointer of C++). The method receives a copy of the reference, which points to the same array: the changes made to the elements of the array are visible to the caller.

  • A method returns at most one value. When a method has to give back several results, it can return them in an array, for example new int[]{q, r}.

Example 8.25: parameters and multiple results

public class Main {

    static void increment(int x) {
        x = x + 1; // Modifies only the local copy
    }

    static void fillWithZeros(int[] a) {
        for (int i = 0; i < a.length; i++) {
            a[i] = 0; // Modifies the array of the caller
        }
    }

    static int[] divide(int n, int m) {
        return new int[]{n / m, n % m}; // Two results in an array
    }

    public static void main(String[] args) {
        int k = 5;
        increment(k);
        System.out.println("After increment: " + k);

        int[] b = {4, 7, 1};
        fillWithZeros(b);
        System.out.println("Array: " + b[0] + " " + b[1] + " " + b[2]);

        int[] qr = divide(17, 5);
        System.out.println("Quotient and remainder: " + qr[0] + " " + qr[1]);
    }
}

Output:

After increment: 5
Array: 0 0 0
Quotient and remainder: 3 2

8.9 A complete algorithm: the maximum value in an array

We now put all the pieces together: a method, a loop, a conditional statement and an array.

We consider the problem of finding the maximum value in an array \(a\) of \(n \ge 1\) integer numbers.

  • This is the pseudo-code of the algorithm FindMaximum of the chapter «Pseudo-code»: the entries are indexed from \(1\) to \(n\).

Algorithm: FindMaximum

Input: An array \(a[1..n]\) of \(n \ge 1\) integer numbers
Output: The maximum value in the array \(a\)
1function FindMaximum(a, n)
2\(max := a[1]\)
3for \(i := 2\) to \(n\) do
4if \(a[i] > max\) then
5\(max \leftarrow a[i]\)
6end
7end
8return \(max\)
9end

  • This is the Java implementation. The elements are indexed from \(0\) to \(n-1\), so the initialization uses a[0] and the loop starts from i = 1. The size \(n\) is not passed as a parameter, because the method obtains it with a.length. The method assumes \(n \ge 1\), as the pseudo-code does: for an empty array the access to a[0] stops the program with an ArrayIndexOutOfBoundsException.

    public class Main {
    
        // Method to find the maximum value in an array
        static int arrayMaxValue(int[] a) {
            int max = a[0]; // Initialize with the first element
    
            for (int i = 1; i < a.length; i++) {
                if (a[i] > max) {
                    max = a[i]; // Update the maximum
                }
            }
    
            return max;
        }
    
        public static void main(String[] args) {
            int[] a = {9, 12, 3, 16, 19, 11, 12};
    
            int max = arrayMaxValue(a);
            System.out.println("Maximum value: " + max);
        }
    }
    

    Output:

    Maximum value: 19
    
  • The test instance can also be generated at random with the class Random of the package java.util: if rand is an object of this class, rand.nextInt(100) returns a random integer between \(0\) and \(99\), so rand.nextInt(100) + 1 is between \(1\) and \(100\). The object created with new Random(2026) starts from the fixed value \(2026\) (the seed), so that every execution produces the same array; the object created with new Random() produces a different array at every execution.

Example 8.26: a random instance

import java.util.Arrays;
import java.util.Random;

public class Main {

    static int arrayMaxValue(int[] a) {
        int max = a[0];
        for (int i = 1; i < a.length; i++) {
            if (a[i] > max) {
                max = a[i];
            }
        }
        return max;
    }

    public static void main(String[] args) {
        int n = 10;  // Size of the array
        int[] a = new int[n];
        Random rand = new Random(2026); // Same random array at every execution
        for (int i = 0; i < n; i++) {
            a[i] = rand.nextInt(100) + 1; // Random integer between 1 and 100
        }

        System.out.println(Arrays.toString(a));
        System.out.println("Maximum value: " + arrayMaxValue(a));
    }
}

Output:

[100, 51, 98, 31, 50, 39, 74, 37, 35, 79]
Maximum value: 100

Example 8.27: step-by-step execution

In each table, the column \(i\) is the index of the Java loop and the column \(i+1\) is the corresponding index of the pseudo-code. The first row is the initialization max = a[0].

Instance 1: \(a = [9, 12, 3, 16, 19, 11, 12]\), \(n=7\)

\(i\) (Java) \(i+1\) (pseudo-code) a[i] a[i] > max? max
– – – – \(9\)
\(1\) \(2\) \(12\) Yes \(12\)
\(2\) \(3\) \(3\) No \(12\)
\(3\) \(4\) \(16\) Yes \(16\)
\(4\) \(5\) \(19\) Yes \(19\)
\(5\) \(6\) \(11\) No \(19\)
\(6\) \(7\) \(12\) No \(19\)

Return: max \(= 19\)

Instance 2: \(a = [3, 7, 2, 9, 1]\), \(n=5\)

\(i\) (Java) \(i+1\) (pseudo-code) a[i] a[i] > max? max
– – – – \(3\)
\(1\) \(2\) \(7\) Yes \(7\)
\(2\) \(3\) \(2\) No \(7\)
\(3\) \(4\) \(9\) Yes \(9\)
\(4\) \(5\) \(1\) No \(9\)

Return: max \(= 9\)

8.10 Bitwise operators

The bitwise operators of the chapter «Introduction to C++» exist in Java with the same symbols and the same meaning: & (AND), | (OR), (XOR), ~ (NOT), < < (left shift) and > > (right shift). The method Integer.toBinaryString(x) returns the binary representation of an integer.

  • A value of type int has \(32\) bits, so ~12 flips \(32\) bits and gives -13; the \(8\)-bit result of C++ is obtained with the mask 0xFF, as in Python.

  • Java has a third shift operator, > > > (unsigned right shift), which always adds zeros on the left, also for negative numbers; for non-negative numbers it coincides with > >.

  • Since a condition must be of type boolean, the test of the least significant bit is written (n & 1) == 1, and not (n & 1) as in C++.

Example 8.28: bitwise operators

int a = 12; // Binary: 1100
int b = 10; // Binary: 1010

System.out.println((a & b) + " " + (a | b) + " " + (a ^ b)); // AND, OR, XOR
System.out.println(Integer.toBinaryString(a & b));           // 1000
System.out.println((5 << 2) + " " + (20 >> 2) + " " + (20 >> 3)); // Shifts
System.out.println(~a + " " + (~a & 0xFF));  // NOT, and its 8-bit version
System.out.println((-8 >> 1) + " " + (-8 >>> 28)); // Signed and unsigned shift

int n = 15;
System.out.println(((n & 1) == 1) ? "odd" : "even"); // Least significant bit

Output:

8 14 6
1000
20 5 2
-13 243
-4 15
odd

The number \(-8\) is stored as \(11\dots11000\) (\(32\) bits): -8 > > 1 keeps the sign and gives \(-4\), while -8 > > > 28 keeps only the \(4\) leftmost bits \(1111\), that is \(15\).

8.11 Java, C++ and Python side by side

The following table summarizes the main differences among the three languages of this part of the course.

C++ Java Python
Execution compiled (g++) compiled into bytecode (javac), executed by the JVM (java) interpreted (python3)
Data types declared declared not declared
Blocks {} {} : and indentation
End of instruction ; ; end of the line
Boolean values true, false (printed 1, 0) true, false True, False
10 / 3 3 3 3.3333333333333335
-7 / 2 (integer) -3 -3 -7 // 2 is -4
Largest integer \(2^{31}-1\) for int \(2^{31}-1\) for int no limit
Logical operators &&, ||, ! &&, ||, ! and, or, not
Collections arrays, freed with delete[] arrays (a.length) and ArrayList, freed automatically lists (len(a)), freed automatically
Out-of-range index not checked exception exception
Several results parameters by reference return of an array return of a tuple
Entry point function main method main of a class top level of the file

Key points of the chapter

  • A Java program is made of classes; it is compiled into bytecode with javac and executed by the JVM with java, starting from the method public static void main(String[] args).

  • Every variable is declared with its data type, which is checked by the compiler; the data type int has \(32\) bits, and the division between two integers is the integer division.

  • Conditional statements (if, else if, else, ?:) and loops (while, for, and the enhanced for) have the same syntax as in C++, but a condition must be of type boolean.

  • The arrays of Java are allocated with new, know their size a.length, are indexed from \(0\) to \(n-1\) and are freed automatically; the class ArrayList provides lists of variable size.

  • Parameters are passed by value; a method that receives an array can modify its elements, and several results are returned together in an array.


Exercises on this chapter: Introduction to Java