JV
PY

Java to Python

10 lessons

Progress0%
1Variables & Types2Classes & OOP3Collections4Exception Handling5File I/O6Functional Programming7Duck Typing and Protocols8Python Ecosystem9Type Hints and Static Analysis10Context Managers and Resources
All Mirror Courses
JV
PY
Type Hints and Static Analysis
MirrorLesson 9 of 10
Lesson 9

Type Hints and Static Analysis

Python's type hints are optional annotations checked by mypy/pyright at static analysis time — unlike Java's mandatory compile-time types.

Introduction

In this lesson, you'll learn about type hints and static analysis in Python. Coming from Java, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
JV
From Java:

In Java, you're familiar with python's type hints are optional annotations checked by mypy/pyright at static analysis time — unlike java's mandatory compile-time types..

PY
In Python:

Python has its own approach to python's type hints are optional annotations checked by mypy/pyright at static analysis time — unlike java's mandatory compile-time types., which we'll explore step by step.

The Python Way

Let's see how Python handles this concept. Here's a typical example:

PY
Python Example
from typing import TypeVar, Callable
from collections.abc import Sequence

T = TypeVar("T")

# Type hints are optional but enable static analysis
def add(a: int, b: int) -> int:
    return a + b

def filter_list(items: Sequence[T], pred: Callable[[T], bool]) -> list[T]:
    return [x for x in items if pred(x)]

names: list[str] = ["Alice", "Bob", "Charlie"]
long_names = filter_list(names, lambda s: len(s) > 4)
print(long_names)  # ['Alice', 'Charlie']

# Union types (Python 3.10+)
def parse(val: str | int) -> int:
    return int(val)

# Optional = T | None
def find(lst: list[str], key: str) -> str | None:
    return next((s for s in lst if s == key), None)

# TypedDict for dict shapes
from typing import TypedDict

class Config(TypedDict):
    host: str
    port: int

cfg: Config = {"host": "localhost", "port": 8080}

Comparing to Java

Here's how you might have written similar code in Java:

JV
Java (What you know)
import java.util.*;
import java.util.function.*;

public class Typed {
    // Types are mandatory; compiler enforces them
    public static int add(int a, int b) { return a + b; }

    public static <T> List<T> filterList(List<T> items, Predicate<T> pred) {
        List<T> result = new ArrayList<>();
        for (T item : items) if (pred.test(item)) result.add(item);
        return result;
    }

    public static void main(String[] args) {
        List<String> names = List.of("Alice", "Bob", "Charlie");
        List<String> long_ = filterList(names, s -> s.length() > 4);
        System.out.println(long_); // [Alice, Charlie]
    }
}
Mirror Card
JV
From Java:

You may be used to different syntax or behavior.

PY
In Python:

Python type hints are optional and not enforced at runtime — use mypy/pyright for static checking

Mirror Card
JV
From Java:

You may be used to different syntax or behavior.

PY
In Python:

Python 3.10+ uses X | Y union syntax; older versions use Optional[X] for X | None and Union[X, Y]

Mirror Card
JV
From Java:

You may be used to different syntax or behavior.

PY
In Python:

TypeVar T creates generic type parameters; Callable[[ArgType], ReturnType] types function values

Mirror Card
JV
From Java:

You may be used to different syntax or behavior.

PY
In Python:

TypedDict creates a typed dict shape without making a class — lighter than @dataclass for pure data

Mirror Card
JV
From Java:

You may be used to different syntax or behavior.

PY
In Python:

Runtime type checking: isinstance(x, int) still works regardless of annotations

Step-by-Step Breakdown

1. Basic Annotations

Add : type after parameter names and -> type before the colon. Annotations don't change runtime behavior — they're metadata for tools.

JV
Java
public static int add(int a, int b) { return a + b; }
PY
Python
def add(a: int, b: int) -> int:
    return a + b

# Totally valid without hints (same runtime behavior):
def add_untyped(a, b):
    return a + b

2. Optional and Union

str | None (Python 3.10+) means the value can be a string or absent. Optional[str] is the older equivalent.

JV
Java
public Optional<String> find(List<String> lst, String key)
PY
Python
from typing import Optional

def find(lst: list[str], key: str) -> str | None:  # 3.10+
    return next((s for s in lst if s == key), None)

# Older style:
def find_old(lst: list[str], key: str) -> Optional[str]:
    ...

3. Generic Functions with TypeVar

TypeVar declares a type variable for generic functions. The constraint T = TypeVar('T') means 'any type, but the same type throughout'.

JV
Java
public static <T> List<T> filter(List<T> items, Predicate<T> pred)
PY
Python
from typing import TypeVar
from collections.abc import Callable, Sequence

T = TypeVar("T")

def filter_seq(items: Sequence[T], pred: Callable[[T], bool]) -> list[T]:
    return [x for x in items if pred(x)]

4. Running mypy

mypy checks type hints statically. Use --strict for strictest mode. Gradual typing: add hints to new code; leave legacy code untyped.

JV
Java
# Java: javac catches type errors at compile time
PY
Python
# Install and run:
pip install mypy
mypy mymodule.py           # basic check
mypy --strict mymodule.py  # strict: all functions must be typed

# pyproject.toml:
# [tool.mypy]
# strict = true
# python_version = "3.12"
Rule of Thumb
Add type hints to all new public functions. Use reveal_type(x) inside your code to ask mypy what type it inferred — helpful for debugging.

Common Mistakes

When coming from Java, developers often make these mistakes:

  • Python type hints are optional and not enforced at runtime — use mypy/pyright for static checking
  • Python 3.10+ uses X | Y union syntax; older versions use Optional[X] for X | None and Union[X, Y]
  • TypeVar T creates generic type parameters; Callable[[ArgType], ReturnType] types function values
Common Pitfall
Don't assume Python works exactly like Java. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • Type hints are optional annotations — mypy/pyright check them statically; Python runtime ignores them
  • X | None (3.10+) or Optional[X] for nullable values; X | Y for union types
  • TypeVar T creates generic type parameter; Callable[[A], R] types function values
  • Run 'mypy --strict' for full coverage; start gradual — annotate new functions first
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your Java code in Python to practice these concepts.
PreviousNext