Java to Python: Classes, Exceptions, and the Standard Library

Part 2 of the Python for Java Developers track. Last updated: October 2026.

You know OOP cold — Python's version is the same ideas with less ceremony. This post maps classes (and the explicit self), the absence of interfaces, the absence of checked exceptions, and a tour of the standard library modules that replace the Java APIs you reach for daily.

Classes: same ideas, less ceremony

No public class boilerplate, no getters/setters required — just a class, an __init__ constructor, and methods. The one surprise is self: Python passes the receiver explicitly as the first parameter (Java's this, but written out):

// Java
public class Order {
    private final String id;
    private double total;
    public Order(String id, double total) {
        this.id = id; this.total = total;
    }
    public String summary() {
        return id + ": $" + total;
    }
}
# Python — __init__ is the constructor, self is the receiver
class Order:
    def __init__(self, id: str, total: float):
        self.id = id
        self.total = total

    def summary(self) -> str:
        return f"{self.id}: ${self.total}"

print(Order("ORD-1", 84.5).summary())
# ORD-1: $84.5

No interfaces — duck typing (and ABC when you want contracts)

Python has no interface keyword because it doesn't need one: if an object has a quack() method, it's a duck. When you do want an explicit contract (framework code, plugin systems), abc.ABC gives you abstract base classes with @abstractmethod:

from abc import ABC, abstractmethod

class Notifier(ABC):                       # the "interface"
    @abstractmethod
    def send(self, message: str) -> None: ...

class EmailNotifier(Notifier):              # the implementation
    def send(self, message: str) -> None:
        print(f"Email: {message}")

def alert(n: Notifier):                    # duck typing also works untyped
    n.send("deploy done")

alert(EmailNotifier())
# Email: deploy done

Exceptions: everything is unchecked

Python has no checked exceptions — nothing like throws IOException forcing callers to catch. Raise with raise, catch specific types with except, and remember the hierarchy root is Exception (never catch bare except: in library code — it swallows KeyboardInterrupt too):

// Java: checked exceptions force handling at every level
public Order load(String id) throws IOException { ... }
# Python: raise and catch what you can handle, let the rest propagate
class OrderNotFound(Exception):
    pass

def load_order(order_id: str) -> dict:
    if order_id != "ORD-1":
        raise OrderNotFound(f"No order {order_id}")
    return {"id": order_id}

try:
    load_order("ORD-9")
except OrderNotFound as e:
    print("Handled:", e)
# Handled: No order ORD-9

Context managers: try-with-resources, generalized

Java's try-with-resources closes one kind of thing. Python's with statement works with any context manager — files, locks, database connections, timers you write yourself:

// Java: try-with-resources
try (BufferedReader br = Files.newBufferedReader(path)) {
    return br.readLine();
}
# Python: with — same guarantee, any resource
from pathlib import Path

with open("orders.csv") as f:      # closed automatically, even on exceptions
    first_line = f.readline()
print(Path("orders.csv").read_text().splitlines()[0] == first_line.strip())
# True

Decorators: annotations that wrap behavior

Java annotations are metadata; Python decorators (the @ syntax) are functions that wrap other functions — they actually change behavior. @property gives you getter-style access, @staticmethod/@classmethod mirror Java's static (with classmethod also receiving the class):

from functools import lru_cache

class Circle:
    def __init__(self, radius: float):
        self.radius = radius

    @property                       # accessed like an attribute: c.diameter
    def diameter(self) -> float:
        return 2 * self.radius

@lru_cache(maxsize=128)              # decorator adding memoization
def fib(n: int) -> int:
    return n if n < 2 else fib(n - 1) + fib(n - 2)

c = Circle(5)
print(c.diameter, fib(20))           # no parentheses on diameter!
# 10 6765

Standard library: your Java API cheat sheet

The batteries are included. Here is where your daily Java APIs live in Python — pathlib replaces java.io/java.nio, datetime replaces java.time, json needs no Jackson:

from pathlib import Path
from datetime import date, timedelta
import json
from collections import Counter, defaultdict

p = Path("data") / "orders.csv"          # / operator joins paths — no Paths.get()
print(p.name, p.suffix)                  # orders.csv .csv

today = date.today()
print(today - timedelta(days=7))         # date arithmetic is just operators

payload = json.loads('{"id": "ORD-1"}')  # no ObjectMapper needed
print(payload["id"], Counter("aabbc")["a"])
# ORD-1 2

grouped = defaultdict(list)              # map of lists without computeIfAbsent
for sku in ["a1", "b2", "a3"]:
    grouped[sku[0]].append(sku)
print(dict(grouped))
# {'a': ['a1', 'a3'], 'b': ['b2']}

Key takeaways

  • Classes need no boilerplate; self is the explicit receiver, __init__ is the constructor.
  • No interface keyword — duck typing by default, abc.ABC when you want a contract.
  • No checked exceptions: raise freely, catch specifically, never use bare except:.
  • with generalizes try-with-resources to any context manager.
  • Decorators wrap behavior (not just metadata): @property, @lru_cache, @staticmethod.
  • Standard library mapping: pathlib → java.nio, datetime → java.time, json → Jackson, collections → Guava-style helpers.

Next in this series: From Maven to pip: Python Tooling, Testing, and Packaging for Java Developers.

Comments

Popular posts from this blog

Java Banking Finance Services and Insurance (BFSI) domain interview questions

JSP Servlet Interview Questions For Freshers Series 1

Java program to check even or odd number