Java to Python Cheat Sheet
Note: AI-generated content, human-reviewed. May contain errors — verify against official docs.
For experienced Java developers learning Python for ADK. This guide maps familiar Java concepts to their Python equivalents, with notes on where things differ.
See also: python-for-adk-learning-plan.md for a structured 2-week curriculum.
Java
Python
Notes
int x = 5;
x = 5 or x: int = 5
No semicolons. Type hints are optional but recommended.
{ ... } blocks
Indentation (4 spaces)
Indentation is syntactically significant.
// comment
# comment
No /* */ block comments; use # per line or """docstrings""".
null
None
Singleton; test with is None, not == None.
true / false
True / False
Capitalized.
System.out.println(x)
print(x)
final int X = 10;
X = 10
Constants are UPPER_CASE by convention only; not enforced.
var x = "hello" (Java 10+)
x = "hello"
Python has always been dynamically typed.
String.format("Hi %s", name)
f"Hi {name}"
f-strings are the preferred approach.
condition ? a : b
a if condition else b
Ternary reads differently.
for (int i = 0; i < n; i++)
for i in range(n):
Python for is always a for-each over an iterable.
switch / case (Java 14+)
match / case (Python 3.10+)
Structural pattern matching; more powerful than Java's switch.
Java
Python
Notes
class Foo { }
class Foo:
No braces; body is indented.
interface IFoo { }
class IFoo(ABC):
Use abc.ABC + @abstractmethod. → decorators deep dive
class Bar extends Foo
class Bar(Foo):
Single inheritance syntax is the same concept.
class Bar implements IFoo
class Bar(IFoo):
No implements; just inherit from the ABC.
this.field
self.field
self is explicit in all instance methods.
public Foo(int x) { }
def __init__(self, x: int):
Constructor is always __init__.
@Override
@override (3.12+)
Optional; from typing. In ADK subclasses (BaseAgent, BaseTool), override by matching the signature exactly — no annotation needed.
final class Foo
@final decorator
From typing; advisory, not enforced at runtime.
static void bar()
@staticmethod
Or @classmethod if you need access to the class.
Foo.class
Foo or type(instance)
Classes are first-class objects in Python.
instanceof
isinstance(obj, Foo)
Also supports tuples: isinstance(obj, (Foo, Bar)).
public / private / protected
Convention: _private, __mangled
No enforced access modifiers. _ prefix = internal.
Multiple constructors (overloading)
Default args or @classmethod factories
Python has no method overloading.
Foo<T> (generics)
Foo[T] with TypeVar or Generic
See Type System below.
Java
Python
Notes
int, long, double
int, float
Python int has arbitrary precision. No primitives vs. wrappers.
String
str
Immutable in both languages.
boolean
bool
List<String>
list[str]
Lowercase built-in generics since Python 3.9.
Map<String, Integer>
dict[str, int]
Set<String>
set[str]
Optional<String>
str | None
Python 3.10+ union syntax. Older: Optional[str].
Object
object
Base of all classes. Any for untyped.
void
-> None
In return type annotation.
enum Color { RED, GREEN }
class Color(Enum):
from enum import Enum.
record Point(int x, int y)
@dataclass or BaseModel
ADK uses Pydantic BaseModel extensively. → pydantic deep dive
sealed interface
@final on subclasses
No direct sealed equivalent.
Annotations (@NotNull)
Type hints + runtime validation
Pydantic validates at runtime; type hints alone do not.
Java
Python
Notes
new ArrayList<>()
[] or list()
Lists are the default mutable sequence.
new HashMap<>()
{} or dict()
Dict literals use {k: v}.
new HashSet<>()
set() or {a, b}
{} alone creates a dict, not a set.
List.of(1, 2, 3)
tuple([1, 2, 3]) or (1, 2, 3)
Tuples are immutable sequences (analogous to List.of()). For a mutable list use [1, 2, 3].
list.add(x)
list.append(x)
list.get(i)
list[i]
Supports negative indexing: list[-1] is last element.
map.get(key)
d[key] or d.get(key)
.get() returns None instead of raising KeyError.
map.put(k, v)
d[k] = v
map.containsKey(k)
k in d
Works for sets and lists too.
stream().filter().map()
List comprehension
[f(x) for x in items if pred(x)] — more idiomatic.
stream().collect()
Comprehension or list(gen)
Generators for lazy evaluation.
Collections.unmodifiableList()
tuple(list)
Or use frozenset for immutable sets.
Arrays.sort(arr)
sorted(arr) or arr.sort()
sorted() returns new list; .sort() mutates in place.
Map.entry() / iteration
d.items()
for k, v in d.items(): — unpacking is idiomatic.
Java
Python
Notes
try { } catch (E e) { }
try: ... except E as e:
catch (A | B e)
except (A, B) as e:
Tuple of exception types.
finally { }
finally:
Same semantics.
throw new E()
raise E()
throws IOException
No equivalent
Python has no checked exceptions. Document in docstrings.
try (var r = ...) (try-with-resources)
with open(...) as f:
Context managers via __enter__/__exit__ or contextlib.
catch (Exception e)
except Exception as e:
Avoid bare except: — it catches SystemExit too.
Custom exception class
class MyError(Exception):
Inherit from Exception, not BaseException.
e.getMessage()
str(e)
Stack trace
traceback module
Or import traceback; traceback.print_exc().
Java
Python
Notes
CompletableFuture<T>
asyncio.Task / await
ADK is async-first. → asyncio deep dive
ExecutorService
asyncio event loop (managed by runtime)
Single-threaded; no thread pool needed for I/O. Never call get_event_loop() — just await or use asyncio.create_task().
Future.get()
await coroutine
Never block on a coroutine; always await.
CompletableFuture.allOf()
asyncio.gather()
Run multiple coroutines concurrently.
synchronized
asyncio.Lock()
For async code. threading.Lock for threaded code (rare in ADK).
Thread
asyncio.create_task()
Tasks are lightweight; no OS threads.
@Async (Spring)
async def
Native language keyword.
Callable<T>
Callable[..., Awaitable[T]]
Or just async def function.
volatile
No equivalent
GIL provides basic visibility; use asyncio primitives.
Thread pool for CPU work
asyncio.to_thread()
Offload CPU-bound work from the event loop.
See 17-concurrency.md for ADK-specific concurrency patterns.
Java
Python
Notes
JUnit 5
pytest
No class required; plain functions work. → testing guide
@Test
def test_something():
Prefix with test_.
@BeforeEach / @AfterEach
@pytest.fixture
Fixtures are injected by name. More flexible than JUnit lifecycle.
@BeforeAll / @AfterAll
@pytest.fixture(scope="module")
Or scope="session" for across all tests.
assertEquals(a, b)
assert a == b
Plain assert; pytest rewrites for rich diffs.
assertThrows(E, () -> ...)
with pytest.raises(E):
Context manager style.
@ParameterizedTest
@pytest.mark.parametrize(...)
Mockito mock()
unittest.mock.Mock()
Or MagicMock, AsyncMock for async.
when(m.foo()).thenReturn(x)
m.foo.return_value = x
Or m.foo.side_effect = ... for dynamic behavior.
verify(m).foo()
m.foo.assert_called_once()
@MockBean (Spring)
monkeypatch or @patch
pytest's monkeypatch fixture or unittest.mock.patch.
@SpringBootTest
@pytest.mark.asyncio
For testing async ADK agents.
See 22-testing.md for ADK-specific testing with MockModel.
Java Concept
ADK Python Equivalent
Notes
Maven / Gradle
pip / uv / poetry
uv is the modern fast alternative. pyproject.toml replaces pom.xml.
Spring Boot Application
Runner + App
Runner is the stateless orchestrator; App is the DI container. → 03-runners.md , 10-apps.md
@RestController
LlmAgent
An agent handles requests and produces responses. → 04-agents.md
@Service
FunctionTool / BaseTool
Business logic wrapped as tools for agents. → 09-tools.md
DTO / Request Body
Pydantic BaseModel
Runtime validation, serialization, schema generation. → pydantic deep dive
@Autowired / DI
Constructor args on LlmAgent
Tools, sub-agents, and config are passed directly. No DI framework.
ApplicationEvent
Event + EventActions
Side effects are data, not method calls. → 07-events.md
HttpSession
Session + SessionService
Session state is a plain dict with scoped keys. → 08-sessions.md
Interceptor / Filter
Callbacks (before_* / after_*)
Six hook points on LlmAgent. → 04-agents.md
Spring Profiles (startup config)
No direct equivalent; closest is app: keys for shared state
Spring Profiles configure the app at startup; ADK state scoping is runtime visibility, not startup config. → 08-sessions.md
@Async + CompletableFuture
async def + await
Everything in ADK is async. → asyncio deep dive
@Scheduled
LoopAgent
Iterative execution until a stopping condition. → 04-agents.md
@Transactional
EventActions.state_delta
State changes are committed atomically with the event. → 07-events.md
Strategy pattern (interface + impls)
BaseLlm, BaseSessionService, etc.
ABC base + multiple concrete implementations throughout ADK.
JUnit + Mockito
pytest + MockModel + AsyncMock
MockModel replaces the LLM for deterministic tests. → 22-testing.md
ObjectMapper (Jackson)
Pydantic model_dump() / model_validate()
Serialization and deserialization built into models.
Lombok @Data
@dataclass or BaseModel
Auto-generated __init__, __repr__, __eq__.
Optional.orElse()
value if value is not None else default
Or just value or default for falsy-safe cases.
Stream.of().map().filter()
Generator expressions / comprehensions
(f(x) for x in items if pred(x)) — lazy by default.
No boilerplate — Python rewards conciseness. If your code looks like Java with Python syntax, refactor.
Duck typing — Check behavior, not type. hasattr(obj, "run") rather than instanceof Runnable.
Everything is an object — Functions, classes, and modules are all objects you can pass around.
Explicit self — Always the first parameter in instance methods. Not a keyword; just a convention.
EAFP over LBYL — "Easier to Ask Forgiveness than Permission." Use try/except rather than checking preconditions.
No checked exceptions — Document exceptions in docstrings; callers choose what to catch.
async/await is foundational — ADK is built on asyncio. Master it early. → asyncio deep dive
See also: glossary.md | 00-onboarding-guide.md | 20-best-practices.md