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

What are the core classes and interfaces of hibernate 4

JSP Servlet Interview Questions For Freshers Series 1

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