Learn Java

Java for Python and JavaScript programmers

You already know how to program, so you do not need loops explained again. This page sets Java next to the language you know, one everyday job at a time, and points out what works differently in Java. Pick your language, read the differences, then start the course wherever it makes sense.
I know

A first program

Python
print("Hello")
Java
void main() {
IO.println("Hello");
}

Since Java 25 a file can be just a main method, run with java Main.java. Most Java you will read still wraps it in public class Main with public static void main(String[] args), and every statement ends with a semicolon.

More in 1. Your first Java program

Running a program

Python
# python3 hello.py
Java
// java Main.java runs one file directly
// javac Main.java && java Main compiles first, then runs

Java checks the whole program before anything runs. A type mistake on line 40 stops the program from starting at all, where Python and JavaScript would only fail when they reach that line.

More in 1. Your first Java program

Variables have a fixed type

Python
count = 3
count = "three" # fine
Java
int count = 3;
count = "three"; // does not compile

A Java variable is declared with a type, and only values of that type fit in it. The compiler checks this before anything runs, so the mistake on the last line never reaches the user. var count = 3; lets Java work out the type, but the type is still fixed.

More in 2. Variables, types, and input/output

Numbers and division

Python
7 / 2 # 3.5
7 // 2 # 3
2 ** 100 # a 31-digit number
Java
7 / 2 // 3
7 / 2.0 // 3.5
Math.pow(2, 100) // 1.2676506002282294E30
Integer.MAX_VALUE + 1 // -2147483648

Dividing two ints in Java throws the fraction away. Whole numbers have fixed sizes: an int wraps around silently past about 2.1 billion, so counts that can get big use long, and exact huge numbers use BigInteger.

Python habit to watch: Python's integers never overflow. Java's do, without any error.

More in 3. Operators, expressions, and casting and 51. Money and exact numbers: BigDecimal and BigInteger

Text and characters

Python
name = 'Ada'
first = name[0] # 'A', a one-letter string
f"{name} is {36}" # 'Ada is 36'
Java
String name = "Ada";
char first = name.charAt(0); // 'A', a char
"%s is %d".formatted(name, 36) // "Ada is 36"
name + " is " + 36 // "Ada is 36"

Java uses double quotes for a String and single quotes for a single char, a separate type. There is no index syntax on strings: use charAt, substring and length().

More in 20. Strings, StringBuilder, StringBuffer and 2. Variables, types, and input/output

Comparing text

Python
name == "Ada"
Java
name.equals("Ada")

In Java, == on two objects asks whether they are the same object in memory, not whether they hold the same text. Use equals for text, and equalsIgnoreCase when case should not matter.

More in 20. Strings, StringBuilder, StringBuffer and 36. equals, hashCode and toString

Conditions must be true or false

Python
if items:
print("not empty")
Java
if (!items.isEmpty()) {
System.out.println("not empty");
}

A Java condition must be a boolean. Numbers, strings, lists and null are never true or false by themselves, so if (items) and if (count) do not compile.

More in 4. Making decisions: if, else and switch

Loops

Python
for i in range(5):
print(i)
for name in names:
print(name)
Java
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
for (String name : names) {
System.out.println(name);
}

The counting loop is the same shape as JavaScript's. The loop over a collection uses a colon and states the element's type.

More in 5. Loops: for, while, do-while

Lists

Python
nums = [3, 1, 2]
nums.append(4)
nums[0] # 3
len(nums) # 4
nums.sort()
Java
List<Integer> nums = new ArrayList<>(List.of(3, 1, 2));
nums.add(4);
nums.get(0) // 3
nums.size() // 4
Collections.sort(nums);

A list holds one type, written in angle brackets, and it must be an object type: List<Integer>, not List<int>. Java converts between int and Integer for you.

More in 7. ArrayList: a list that can grow and 32. Wrapper classes and autoboxing

Arrays have a fixed size

Python
# Python lists always grow
scores = [0] * 5
Java
int[] scores = new int[5]; // five zeros, forever five
scores.length // 5
scores[5] = 1; // ArrayIndexOutOfBoundsException

A Java array keeps the length it was made with. Reaching past the end throws an exception instead of growing the array or giving undefined. When you need to add and remove, use an ArrayList.

More in 6. Arrays, one dimension and 7. ArrayList: a list that can grow

Dictionaries and maps

Python
ages = {"Ada": 36}
ages["Alan"] = 41
ages.get("Bob") # None
ages["Bob"] # KeyError
Java
Map<String, Integer> ages = new HashMap<>();
ages.put("Ada", 36);
ages.put("Alan", 41);
ages.get("Bob") // null
ages.getOrDefault("Bob", 0) // 0

A missing key gives null. Unboxing that null into an int throws a NullPointerException, so reach for getOrDefault or containsKey. A HashMap keeps no order; a LinkedHashMap keeps insertion order like a Python dict.

More in 35. HashMap and HashSet: finding things fast

Functions are methods

Python
def area(w, h=1):
return w * h
Java
static int area(int w, int h) {
return w * h;
}
static int area(int w) {
return area(w, 1);
}

Every Java function is a method inside a class, with typed parameters and a return type. There are no default argument values: write a second method with the same name and fewer parameters (an overload).

More in 12. Methods: parameters and return values

Nothing there: null

Python
name = None
name.upper() # AttributeError
Java
String name = null;
name.toUpperCase(); // NullPointerException:
// Cannot invoke "String.toUpperCase()" because "name" is null

Any object variable can hold null, and calling a method on it fails while the program runs. Java's message names the variable that was null. Optional is the way to say in a method's type that a result may be missing.

More in 9. Reading errors and debugging and 55. Optional: a value that might be missing

Classes

Python
class Dog:
def __init__(self, name):
self.name = name
def speak(self):
return self.name + " says woof"
Java
class Dog {
private final String name;
Dog(String name) {
this.name = name;
}
String speak() {
return name + " says woof";
}
}

Fields are declared with their types before they are used, and private keeps them inside the class. The constructor is named after the class. Inside a method, this. is only needed when a parameter has the same name as a field.

Python habit to watch: There is no self parameter: the object is this, and it is there without being listed.

More in 11. Creating classes and objects, 13. Constructors and 14. Access modifiers and encapsulation

Data classes

Python
from dataclasses import dataclass
@dataclass(frozen=True)
class Point:
x: int
y: int
Java
record Point(int x, int y) {}
Point p = new Point(1, 2);
p.x() // 1
p // Point[x=1, y=2]

A record is a class that only holds data. One line gives it a constructor, read-only accessors, equals, hashCode and toString.

More in 29. Records: data classes in one line

Lambdas

Python
double = lambda x: x * 2
sorted(words, key=len)
Java
Function<Integer, Integer> doubler = x -> x * 2;
doubler.apply(4) // 8
words.sort(Comparator.comparing(String::length));

A Java lambda uses a thin arrow -> and always has a type: a functional interface such as Function, Predicate or Comparator. You call it through that interface's method, such as apply.

More in 28. Enums, lambdas, and functional interfaces and 37. Comparable, Comparator and sorting

Transforming a collection

Python
[w.upper() for w in words if len(w) > 3]
Java
words.stream()
.filter(w -> w.length() > 3)
.map(String::toUpperCase)
.toList()

Streams play the part of comprehensions and array methods. They do nothing until the last call, such as toList(), asks for a result.

More in 53. Streams: processing collections step by step and 54. Collectors and stream recipes

Errors and exceptions

Python
try:
n = int(text)
except ValueError as e:
print("Not a number:", e)
Java
try {
int n = Integer.parseInt(text);
} catch (NumberFormatException e) {
System.out.println("Not a number: " + e.getMessage());
}

Some Java exceptions are checked: a method that can throw one, such as reading a file, must say so with throws, and its callers must catch it or pass it on. The compiler enforces this.

More in 48. Exception handling

Matching values

Python
match command:
case "start" | "go":
run()
case _:
print("unknown")
Java
switch (command) {
case "start", "go" -> run();
default -> System.out.println("unknown");
}

The arrow form of switch never falls through, so it needs no break. It can also produce a value: int days = switch (month) { ... };.

More in 4. Making decisions: if, else and switch and 30. Sealed types and pattern matching

Three ways to ask for a length

Python
len(text)
len(nums)
len(scores)
Java
text.length() // a String: a method
nums.size() // a List or other collection
scores.length // an array: a field, no parentheses

A String has the method length(), a collection has size(), and an array has the field length. The compiler tells you when you pick the wrong one.

More in 20. Strings, StringBuilder, StringBuffer, 6. Arrays, one dimension and 7. ArrayList: a list that can grow