Python To Java
Python To Java
Like the hitchhiker’s guide to the galaxy… but the Python developer’s guide to Java basics.
Enjoy.
Language Relationships
Python is based on C, and Java is based on C++ (which is based on C). Java looks more like C
than Python does, though.
Python
if b > a:
print("b is greater than a")
○ Java
■ In Java, code blocks are defined by braces ({}). Braces are opened and
closed at the beginning and end respectively of blocks of code that need
to be grouped together, including the bodies of:
■ Class declarations
■ Function/method declarations
■ Control structures (e.g. conditionals, loops)
■ Note: indentation doesn’t have any semantic significance in Java
whatsoever, however is important for human readability
■ Example:
Java
if (b > a) {
[Link]("b is greater than a");
}
● Statement ends
○ In Python, no special syntax is required at the end of statements
○ In Java, every statement must end with a semicolon
● Comments
○ Single-line comment:
■ In Python, single-line comments are written with a preceding ‘#’
■ In java, single-line comments are written with a preceding (‘//’)
○ Multi-line comments
■ In Python, multi-line comments are written with a preceding ‘#’ at the start
of each line
■ In java, a multiline comment is written with ‘/*...*/’, with the body of the
comment replacing the ellipsis
○ JavaDoc comments
■ JavaDoc is a documentation type specific to Java. It is a documentation
generator that uses specially formatted comments known as JavaDoc
comments in the source code to generate API documentation in HTML
format.
■ JavaDoc comments are placed directly above the definition of a class,
interface, method, or field that they are documenting. A javadoc comment
is written with ‘/**...*/’, with the body of the comment replacing the ellipsis
■ Example:
Java
/**
* Description of the method being documented.
*
* @param param1 param description
* @param param2 param description
* @return what is returned by the method
*
*/
method signature...
Type System
● Python
○ Python is dynamically typed.
○ In dynamically typed languages, type checking occurs at runtime. In practice this
means that you don’t have to specify a variable’s type when you declare it. The
type of a variable in Python is inferred, meaning it is automatically deduced
during compile time from a context where it’s not explicitly declared.
○ This also means that you can change the type of a variable at any point in your
code. For example, you can initially set a variable x to an integer value and later
in your code assign the same variable to a string value.
○ Example:
Python
x = 7 # x is an integer with value 7
x = "hello" # x is now a string with value "hello"
● Java
○ Java, on the other hand, is strictly statically typed.
○ In statically typed languages, the type of each variable must be known at compile
time, before the program is actually run. In practice this means that you must
specify the type of each variable when you declare it.
○ If you try to assign the wrong type to a variable (e.g. assigning a string to an
integer variable) the compiler will throw an error and the code won’t compile.
○ The benefit of this is the enablement of Java compile-time type analysis, which
leads to greater code safety and fewer exceptions at runtime, albeit at the cost of
moderately lesser flexibility.
○ Example:
Java
int x = 7; // x is an integer with value 7
x = "hello"; // an exception is thrown
public Y Y Y Y
protected Y Y Y N
default Y Y N N
private Y N N N
○ Usage
■ It is best practice to assign an access modifier to every class, interface,
field, method, and constructor
■ Typically best practice to grant the minimum level of access necessary for
the element to be utilized properly
● All class fields should be private by default - you should never
expose a class member as public with the exception of ‘public final
static’ constants (notes below on these keywords) meant for
external consumption
■ We use the Lombok third party library to cut down on verbosity/boilerplate
and automatically apply access modifiers across a class
○ Java
■ In java, the ‘new’ keyword is used to create new objects (instances of a
class). The ‘new’ keyword is always followed by a call to a constructor of
the class, which initializes the new object.
■ In Java, therefore, each object declaration requires the type of the object
to be specified and the use of the new keyword before making a call to
the class’ constructor
■ Example:
Java
MyClass newObj = new MyClass();
● Method declaration
○ Python
■ In Python, method declaration includes the following: the def keyword to
specify that you’re declaring a method followed by the name of the
method, the parameter names (notably without need for parameter types)
enclosed within parentheses, and then the method body following a
colon.
■ Example:
Python
def add(a, b):
return a + b
○ Java
■ In Java, method declaration includes the following: the optional
specification of an access modifier, a return type, a function name,
parameters, notably including parameter types as well as names, and
lastly the body of the method enclosed within braces
■ Notably, method declaration in Java does not require any equivalent of
the Python ‘def’ keyword.
■ Example:
Java
public int add (int a, int b) {
return a + b;
}
Python
def func_with_args(*args):
for arg in args:
print(arg)
func_with_args(1, 2, 3, 4)
def func_with_kwargs(**kwargs):
for key, value in [Link]():
print(f"{key} = {value}")
Java
public class MathOperations {
● Re the above example: when you invoke the add method, the
Java compiler will automatically determine which version of the
above add methods to use based on the method signature (name
of the method + the number and type of its parameters)
■ In general we want to avoid overloading a single method too much
because it can clutter code and make it difficult to understand.
● Returning from methods
○ Python
■ In Python, the ‘return’ keyword is used to exit from a method and
optionally return a value
■ A method will return ‘None’ by default if no return is specified
○ Java
■ Java also uses the ‘return’ keyword to exit from a method and optionally
return a value, as in Python
■ Unlike Python, a method with a non-void return type must explicitly return
a value in Java. Failure to do so will result in a compile time error.
■ If the method is declared to have a void return type then the ‘return’
keyword is not strictly necessary and the method will return automatically
when it reaches the end of the method.
● Constructors
○ Overview
■ In both Python and Java, constructors are used for instantiating an object
○ Python
■ In Python, the __init__ method is automatically called when an object of
the class is created. It is analogous to a constructor.
■ It can take any number of parameters, but the first parameter is always
‘self’.
■ Example:
Python
class MyClass:
def __init__(self, param1="hello world", param2=7):
self.param1 = param1
self.param2 = param2
○ Java
■ In Java, a constructor is similarly a block of code that initializes a newly
created object.
■ A constructor in Java resembles an instance method but without a return
type.
■ If no constructors are defined in the class, the Java compiler automatically
provides a default no-args constructor:
■ In this case, the line Class var = new Class() would utilize the
default no-args constructor Java uses a default no-args
constructor.
■ This constructor takes no arguments and is often used to provide
default values for the object's attributes.
■ If any other constructor is defined, the default no-args constructor
must be explicitly declared if it's needed.
■ You can also define as many constructors as you like with different input
parameters and parameter types, a process known as constructor
overloading.
■ Example:
Java
public class TestClass {
String param_1;
int param_2;
Python
class Student:
def __init__(self, name):
[Link] = name # 'self' refers to the current instance
def get_name(self):
return [Link] # 'self' refers to the current instance
student = Student("Alice")
print(student.get_name()) # prints: Alice
○ Java
■ The 'this' keyword is the same function in Java, i.e. it is a reference to the
current object.
■ In Java, ‘this’ is a keyword enforced by the language
■ The 'this' keyword can be omitted when there is no ambiguity with local
variables. As such, unlike in Python, it does not need to be included as
the first parameter in instance methods.
■ Java's 'this' can be used to call other constructors within the same class,
which doesn't have a direct equivalent in Python.
■ Example:
Java
public class Student {
private String name;
Python
class MyClass:
class_var = 0 # This is a class variable (shared across all instances)
def increment_class_var(self):
MyClass.class_var += 1
print("Class variable value:", MyClass.class_var)
def increment_instance_var(self):
self.instance_var += 1
print("Instance variable value:", self.instance_var)
@classmethod
def show_class_var(cls):
print("Class variable (from class method):", cls.class_var)
@staticmethod
def add_numbers(a, b):
return a + b
obj1 = MyClass(10)
obj1.increment_class_var() # Increments the class variable and prints it
obj1.increment_instance_var() # Increments the instance variable and prints it
obj1.show_class_var() # Prints the class variable using a class method
result = obj1.add_numbers(5, 3) # Calls the static method
print("Sum from static method:", result) # Prints: Sum from static method: 8
○ Java
■ Variables
● Java features static variables for this purpose.
● Static fields in Java also belong to the class itself.
● Java static variables are also, by default, accessible both by
instances of the class and by the class itself.
● Static variables in Java are preceded by the keyword static
■ Methods
● Java also features static methods.
● Static methods in Java also belong to the class itself and are
accessible only via the class itself, not via an instance of the class.
● Static methods are similarly preceded by the keyword static
● Static methods can call other static methods or access static data
within the same class or other classes, and they can call
non-static methods and access non-static data via an instance of
a class.
● Java does not have a direct equivalent to Python’s class methods.
While static methods in Java are similar to static methods in
Python, there’s no special method type in Java that takes the
class itself as a parameter
● Note: we like to use static methods at Ethic because it enforces an
immutable style of programming in which we’re not relying on
class instance objects to do the work but rather on class
components that take some input, do some work, and spit out a
result
■ Example:
Java
public class Car {
private static int totalCars = 0; // Static field
private String color; // Non-static field
[Link]([Link]()); // prints: 2
[Link]([Link]()); // prints: Red
[Link]([Link]()); // prints: Blue
}
}
Python
from typing import List
■ Other than type hints, which are similar, there is no direct equivalent to
Java's generics, as the dynamic typing system in Python provides the
needed flexibility with types by default. Type hints are completely optional
and not enforced at runtime.
○ Java
■ Unlike Python, Java’s type system is strictly static, requiring the type of
every variable to be known at compile time.
■ Generics in Java provide a way to create data structures and methods
that can hold or operate on objects of various types, maintaining type
safety.
■ Java necessitates the use of generics to achieve similar dynamic typing
flexibility to Python given its strictly static type system.
■ Generic classes:
● A generic class accepts and operates on a placeholder type, thus
allowing instances of this class to be created with any type.
● Example:
Java
public class Collection<T> {
private T t;
public T get() {
return t;
}
}
Java
public static <T> void print(T element) {
[Link](element);
}
Java
public static void main(String[] args){
//body
}
Basic Operations
● Basic Common Methods
○ Printing: [Link](elementToPrint);
○ Equality checks (see below section on Equality Checking):
■ Two objects: [Link](object1, object2);
■ Two Arrays: [Link](object1, object2);
○ Null check: [Link](object);
○ Conversion to String: [Link]();
○ Parsing and converting strings:
■ To Integer: [Link]("123");
■ To Double: [Link]("123.45");
○ Collection sorting: [Link](Collection);
○ Exiting the program: [Link](exitCode);
● Conditionals
○ Java conditionals work similarly to Python’s with just slightly varying syntax
○ If/else:
■ Python:
Python
if condition:
#...
elif conditoin:
#...
else:
#...
■ Java:
Java
if (condition) {
//...
} else if (condition) {
//...
} else {
//...
}
■
In java, parentheses are required around the condition and braces
around the body of the if or else
■ Java uses the ‘else if’ keyword as opposed to the Python ‘elif’
○ Ternary operator
■ Python: result = value_if_true if condition else
value_if_false
■ Java:
■ In java, parentheses are required around the condition, the ‘if’ and
‘else’ are replaced by ‘?’ and ‘:’, and the formatting is slightly
different
■ Example: int result = (condition) ? value_if_true :
value_if_false
■ Best practice not to nest ternary operators
● Looping
○ For loop:
■ Python:
■ Python has several styles of for-loop, including the standard for
loop, the enumerate loop, and the range loop.
■ Standard for-loop:
○ This is used to iterate over elements in an iterable like a
list, tuple, or string.
Python
for value in iterable:
# loop steps through each element in the collection
■ Enumerate loop:
○ This is used if you need to access the index as well as the
value.
Python
for index, value in enumerate(iterable):
# loop steps through each element in the collection and increments index
■ Range loop:
○ This is used to loop over a sequence of numbers, whether
to use as indexes of an iterable or separately.
Python
for i in range(10):
# value of i increments with each loop
■ Java:
■ Java has three primary styles of for-loop (that we use here at
Ethic): a traditional, C-style for-loop, the enhanced for-each loop,
and the Stream API for-loop.
■ Traditional for-loop:
○ The traditional, C-style for-loop has three parts:
initialization, condition, and increment/decrement.
○ It requires braces around the body and parentheses
around the condition.
○ This is similar in functionality to Python’s Range loop.
Python
for (int i = 0; i < 10; i++) {
//value of i increments with each loop
}
Python
List<Integer> numbers = [Link](1, 2, 3, 4, 5);
Python
[Link](value -> {
// loop steps through each element in the collection
});
Python
while condition:
#code to execute while the condition is true
Python
while condition:
if some_other_condition:
break #while loop ends
#code to execute
if yet_another_condition:
continue #while loop skips to the next iteration
■ While-else loop:
○ In a Python while-else loop, the ‘else’ block is executed if
the loop is terminated because the condition becomes
false and is skipped if the loop is exited via a break
statement.
Python
while condition:
# code to execute while the condition is true
else:
# code to execute when condition is False
■ Java
■ In Java, while loops are very similar in structure and function. It
differs only really in syntax.
■ Note: we tend not to use these very often at Ethic, and only really
for lower-level code
■ Basic while loop:
○ This is very similar to Python’s Basic while loop.
Java
while (condition) {
//code to execute while the condition is true
}
■ Do-while loop:
○ This is unique to Java (and some other C-like languages)
where the loop body is guaranteed to execute at least
once, even if the condition is initially false.
Java
do {
// code to execute
} while (condition);
Python
match expression:
case pattern1:
# code block for pattern1
case pattern2:
# code block for pattern2
■ Patterns:
■ Patterns can be a wide variety of types and structures
○ Literal patterns: matching exact values.
○ Variable patterns: matching any value and binding it to a
variable.
○ Sequence patterns: matching lists or tuples.
○ Mapping patterns: matching dictionaries.
○ Class patterns: matching instances of classes.
○ Wildcard pattern: matching anything.
■ Combining patterns: you can use the ‘|’ operator to combine
patterns.
■ Guards: guards are additional conditions that can be added to a
pattern using the if keyword.
■ Examples:
Python
match expression:
case 42: #literal pattern
case y: #variable pattern
case [0, 0]: #sequence pattern
case {"name": "Alice", "age": age}: #mapping pattern
case Circle(radius=r): #class pattern
case 1 | 0: #combining literal patterns
case y if y > 10: #guards on a variable pattern
case _: #wildcard pattern
○ Java
■ In Java, the switch/case block provides a similar multi-way branch,
allowing you to check for equality between a variable or expression
(switch statement) and a series of values (cases) and execute different
possible blocks of code depending on which cases match the switch
expression.
■ The switch expression must evaluate to a char/Character, byte/Byte,
short/Short, int/Integer, String, or an enum value.
■ default block:
■ The code in the ‘default’ block is executed if the value of the
variable/expression being checked does not match any of the
cases.
■ Serves the same functionality as the Python wildcard pattern.
■ Note: it is best practice to ALWAYS add a default block, often just
to throw an exception if none of the cases match
■ Fall-through
■ In the Java switch/case block, unlike in the Python match/case
block, once a pattern is matched, the execution of the switch/case
block does not exit.
■ In the Java switch/case block, unlike in the Python match/case
block, once a case is matched, the execution of the switch/case
block does not exit automatically.
■ Rather, the control will ‘fall through’ from one case statement to
the next, executing the code under each case until a break
statement is encountered or the end of the block is reached. This
process is called “fall-through”.
■ break statements:
■ The break statement in a switch/case block, similar to the effect of
the same keyword in a while loop, exits the block.
■ This is useful and necessary because of fall-through: you may
want to exit execution of the block after a case is matched against
the switch expression rather than continuing on to further case
statements.
■ Example:
Java
switch (variable) {
case value1:
//code to execute if the switch expression matches value1
break; //execution of the block exits
case value3:
//code to execute if the switch expression matches value3
case value4:
//code to execute if the switch expression matches value4
//because of the lack of break statement in the previous case, if
the switch expression matches both value3 and value4 then both the 'case
value3' and 'case value4' code blocks will be executed)
...
default:
//code to execute only if no cases are matched against the switch
expression
}
● Casting variables
○ Python
■ In Python, casting between types is often done using constructor
functions like int(), float(), and str().
■ Python is dynamically typed so variables don’t have a fixed type, but you
may need to convert between types in different situations.
■ Examples:
Python
#Casting a float to an integer
x = 1.2
y = int(x) # y is 1
○ Java
■ In Java, casting is more rigid due to the statically typed nature of the
language.
■ There are two types of casting:
■ Primitive type casting
○ Implicit (widening) casting:
■ This involves converting from a smaller primitive
type to a larger type that can represent more values
(e.g. int to float).
■ This is done automatically by Java.
Java
int myInt = 9;
double myDouble = myInt; // Automatically casts the int to a double
Java
double myDouble = 3.14;
int myInt = (int) myDouble; // myInt is 3
Java
Object myObject = new String("Hello");
String myString = (String) myObject; // Valid cast as String is an Object
■ Autoboxing/unboxing
■ Java allows for automatic conversion between primitive types and
their corresponding wrapper classes (e.g. from int to Integer).
This is called autoboxing/unboxing.
● Lambdas
○ Overview
■ A lambda expression is a convenient syntax available in many
programming languages for writing short functions.
■ Lambda expressions do for functions what object-oriented programing
does for objects: it makes a function something you can assign to a
variable.
○ Python
■ In Python, lambda functions are defined using the lambda keyword
followed by a list of arguments, a colon, and an expression to execute
with the arguments.
■ Example:
Python
add_one = lambda x: x + 1
result = add_one(1) # result is now 2
■ Lambdas in Python are often used with higher-order functions like map,
filter, and reduce, for example:
Python
numbers = [1, 2, 3, 4]
squares = map(lambda x: x**2, numbers) # squares is [1, 4, 9, 16]
○ Java
■ Java has lambda functions similar to those in Python.
■ The syntax of lambda functions in Java is slightly different, involving no
need for a keyword. They simply include the arguments listed within
parentheses, a ‘->’ symbol, and the expression to be executed.
■ If a lambda expression requires only a single line of body code
then it follows this syntax.
■ If the lambda expression requires multiple lines of body code then
the body must be contained within brackets (‘{}’).
■ Java lambdas can be executed using builtin methods on the type of the
lambda (see below for Java lambda types). They can also be passed in
as function arguments.
■ Example:
Java
Function<Integer, Integer> addOne = (x) -> x + 1;
int result1 = [Link](1); // result1 is 2
Python
# Increment
x = 1
x += 1 # x is now 2
# Decrement
y = 2
y -= 1 # y is now 1
○ Java
■ Java allows for the assignment += and -= operator syntax for
incrementing and decrementing variables as in Python.
■ It also includes specific in-built increment (++) and decrement (--)
operators, which can be placed preceding or following the variable to be
incremented or decremented.
■ Example:
Java
// Increment
int x = 1;
x += 1; // x is now 2
x++; // x is now 3
++x; // x is now 4
// Decrement
int y = 4;
y -= 1; // y is now 3
y--; // y is now 2
--y; // y is now 1
● Equality Checking
○ Python
■ In Python, the == operator checks for value equality. If two objects have
the same content, then obj1 == obj2 will return True.
■ The is keyword, on the other hand, checks for reference equality. If two
references (variables) point to the same object in memory then it will
return True.
■ Example:
Python
list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = list1
print(list1 == list2) # True, because the contents of the lists are the same
print(list1 is list2) # False, because they are two different objects in memory
print (list3 is list1) # True, because they are the same object in memory
○ Java
■ Conversely, in Java, the == operator checks for reference equality. If two
references (variables) point to the same object in memory then it will
return true. If two strings are identical due to string interning (see notes
below), they might be the same in memory, but that's not a guarantee.
■ The .equals() method, on the other hand, checks for value equality. It will
return true if two objects are equivalent in content, even if they are
different objects in memory. Every class in Java should (though it is not
required) have a .equals() method implemented for this purpose.
■ String interning:
● Java maintains a special pool of strings (the string pool), which is
part of the heap memory. When you create a string literal (i.e., a
string defined between double quotes), Java checks the string
pool to see if an identical string already exists. If it does, Java will
simply return a reference to the cached string object. Otherwise, it
adds the new string to the pool.
● This behavior is why sometimes you’ll see two string literals with
the same content reference the same object in memory, making
str1 == str2 return true.
● This is an optimization that helps save memory since strings are
immutable in Java.
● This behavior is specific to string literals and doesn’t apply whens
trings are created using the new keyword. If you create a new
string using the new keyword then you’ll bypass the string pool and
automatically create a new object in memory.
■ Example:
Java
String str1 = "hello"
String str2 = new String("hello");
String str3 = str1
String str4 = "hello"
Inheritance
● Overview
○ Inheritance is an OOP mechanism that allows one class to inherit the attributes
(fields) and behaviors (methods) of another class. This forms a parent-child
relationship where the class that is inherited is known as the super/parentclass
and the class that does the inheriting is known as the sub/childclass.
○ In general at Ethic we prefer composition, a design concept that models a "has-a"
relationship. It enables you to reuse code by containing instances of other
classes within your class. This often leads to a more flexible structure since it's
easier to change class relationships without affecting other parts of your code.
○ However, inheritance can still be very useful in certain contexts, especially when
the parent-child relationship is natural and clear.
● Python inheritance
○ The abc (Abstract Base Classes) module of Python enables the definition of
interfaces and abstract classes which other related classes can inherit
■ Interfaces and abstract classes are created by defining a class that
inherits ABC (see following example)
○ Abstract methods can be created within abstract classes and interfaces by using
the @abstractmethod decorator
○ Abstract classes
■ Can be created through the use of abstract base classes containing one
or more abstract methods (a method declared without an implementation)
and 0 or more non-abstract methods
■ Cannot be instantiated as objects
■ Purpose is to be inherited by other classes
■ Other classes can inherit any number of abstract classes
○ Interfaces
■ Can be mimicked through the use of abstract base classes with entirely
abstract methods
○ Inheriting abstract classes and interfaces
■ Subclasses can inherit from abstract classes or implement interfaces in
Python by including the abstract base class or interface name in the class
definition. This is done by placing the name of the abstract base class or
interface in parentheses after the name of the subclass.
○ Example:
Python
from abc import ABC, abstractmethod
class AbstractClassExample(ABC):
@abstractmethod
def do_something(self):
pass
class Subclass(AbstractClassExample):
def do_something(self):
print("The subclass is doing something")
● Java inheritance
○ Abstract methods
■ Abstract methods are methods that possess a method signature but no
method body / implementation (see below example of an abstract class
for an example)
■ Abstract methods can be created using the abstract keyword together
with a method signature and no method implementation
○ Abstract classes
■ Can be declared using the abstract keyword at the beginning of the class
definition
■ Can include both abstract methods and non-abstract methods
■ Cannot be instantiated as objects
■ Purpose is to be inherited by other classes
■ A class can only inherit 1 abstract class
■ Declared fields can be non-static and non-final, unlike interfaces
■ This allows for different subclasses implementing the abstract
class to have these fields with unique values
■ Example:
Java
abstract class Animal {
abstract void speak(); //abstract method
}
○ Interfaces
■ In java, an Interface is another special type of class intended for
inheritance purposes.
■ Like an abstract class, they cannot be instantiated
■ Can have only abstract, default, and static methods.
■ All declared fields are static and final (have to instantiate them with a
value and the same value applies to every object implementing that
interface)
■ Purpose is to be inherited by other classes
■ A class can inherit multiple interfaces
■ Example:
Java
interface Movable {
void move();
}
interface Machine {
void start();
}
Java
//a java class that inherits a single interface
class Vehicle implements Movable {
public void move() {
[Link]("skrt");
}
}
Exceptions
● Throwing errors and exceptions
○ Python
■ In Python, exceptions are thrown using the raise keyword.
■ You can raise a specific exception by creating an instance of the
exception class, optionally providing an error message.
■ Example:
Python
if x < 0:
raise ValueError("x cannot be negative")
○ Java
■ In Java, you can manually throw an exception using the throw keyword.
■ You can similarly throw a specific exception by creating an instance of the
exception class, optionally providing an error message.
■ Example:
Java
if (x < 0) {
throw new IllegalArgumentException("x cannot be negative");
}
● Exception handling
○ Python
■ In Python, exception handling is typically done using a try/except block in
order to catch exceptions that might be thrown as your program executes.
■ The ‘try’ block includes the code to execute that might cause an
exception.
■ The ‘except’ block includes the code to execute if an exception occurs.
You can catch specific exception types or all exceptions.
■ An ‘else’ block, as is optional, includes code to execute if no exception
occurs. This code is always executed if no exception occurs.
■ A ‘finally’ block, as is also optional, includes code that is ALWAYS
executed after the code in the previous blocks, regardless of whether or
not an exception occurs. This is typically used for cleanup actions.
■ Example:
Python
try:
# Code that might throw an exception
except ExceptionType as e:
# Code to handle the exception, e.g.:
print(e)
else:
# Code to run if no exception occurs
finally:
# Code that will always run, like closing a file
Java
try {
// Code that might throw an exception
} catch (SpecificException e) {
// Handle a specific exception, e.g. through:
[Link]();
} catch (Exception e) {
// Handle all other exceptions
[Link]();
} finally {
// Code that will always run, like closing a file
}
■ Note: exception handling in Java is not always optional, and certain kinds
of exceptions (checked exceptions - see below for notes) are required to
be handled or declared by the programmer. There is compile-time
checking to ensure that these kinds of exceptions are handled or
declared.
● Java checked vs unchecked exceptions
○ Java has two types of exceptions: check and unchecked exceptions.
○ Checked exceptions:
■ Represent invalid conditions in areas outside the immediate control of the
program, e.g. IOException and FileNotFoundException.
■ Java forces you to wrap these in a try/catch or declare them in a method
signature using the throws keyword, thus allowing the method’s caller to
handle them (notes on this in the following section).
○ Unchecked exceptions:
■ Typically errors in your code or bugs (e.g. null pointer exception or array
index out of bounds), e.g. RuntimeException and IllegalStateException.
■ At Ethic we mostly lean on IllegalStateException
■ These are exceptions you don’t have to explicitly surround with a try/catch
in your code or declare in the method signature.
● Java method exception declaration
○ In some cases with checked exceptions in Java, you want to delegate
responsibility for handling the exception to the calling method. In this case you
declare your method as throwing that type of exception
○ Example:
Java
public void readFromFile(String filename) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(filename));
String line;
while ((line = [Link]()) != null) {
[Link](line);
}
[Link]();
}
Performance
● Python
○ Python is an interpreted language. This means that the code is executed
line-by-line directly by the interpreter at runtime. There's no separate compilation
step - the source code is directly executed.
○ This results in generally slower runtimes than Java.
○ This does, however, allow for more flexibility and often easier debugging, as
changes can be made to the code and immediately run without the need to
recompile. It also makes the development process somewhat simpler and
platform-independent as there's no need to compile the code for different
platforms.
● Java
○ Java is a compiled language, meaning that the source code is first compiled to
bytecode by a compiler before the Java Virtual Machine (JVM) then interprets or
further compiles this bytecode and executes it at runtime. This compilation
happens before runtime and is known as Just-in-Time compilation.
○ This results in generally faster execution times in Java compared to Python.
○ This design also allows Java to maintain some platform independence (“Write
Once, Run Anywhere”) while benefiting from the speed of compiled execution.
○ This does, however, result in generally slower build times. Additionally, changes
to the code require recompilation. Also, compiled code may need to be targeted
to specific platforms or architectures, which can reduce portability.
JDK
● The JDK is a software development kit (SDK) used for developing Java applications and
applets
● Provides the tools you need to write and run Java programs
● Includes/encapsulates the Java Runtime Environment (JRE), Java Virtual Machine
(JVM), standard libraries, an interpreter/loader (java), a compiler (javac), an archiver
(jar), debugger, and the Java Virtual Machine (JVM) amongst other tools
○ JRE:
■ Provides the libraries, the JVM, and other components necessary to run
compiled Java applications
■ Does not include any of the development tools that come with the JDK,
such as compilers or debuggers
■ If you’re just running Java applications you’d only need the JRE but if
you’re developing those applications you need the JDK
○ JVM:
■ The JVM is a virtual machine that interprets Java bytecode and executes
it as a program
■ Equivalent to the Python interpreter
○ java: the Java application launcher which executes java classes
■ Similar to running a Python script in the terminal with the python
command
○ javac: the Java compiler which converts source code into Java Bytecode that can
be executed by the JVM
■ Similar to the Python interpreter converting Python scripts to bytecode
before executing them
● Python doesn’t have separate entities such as JDK and JRE as Python’s interpreter can
execute the Python scripts directly, so when you install Python you’re effectively
installing the equivalent of the Java JDK and JRE together
Additional Differences
● Python Slice notation
○ In Python, you can use slice notation to easily and quickly access subsections of
sequences (like lists, strings, and tuples) by specifying a range of indices.
■ E.g. my_list[2:5] will get elements from the 3rd to the 5th in my_list
○ This syntax is not available in Java. Instead you would need to use a loop or
builtin methods (e.g. [Link](startIndex, endIndex)) to achieve the
same result.
● Python List comprehension
○ List comprehensions are a powerful Python feature that allow you to create and
manipulate lists on-the-fly in a concise and readable way.
○ Java does not have an equivalent feature. Streams (via Java’s Stream API) bring
some of the list comprehension flavor in terms of the modularity of
combining/chaining operations, but not in quite as compact and terse of a style.
Similar operations could also be done in explicit loops.
● Java Stream API
○ Java's Stream API, introduced in Java 8, is a powerful feature that allows for
functional-style operations on sequences of elements, such as collections.
○ The Stream API brings a new abstraction of data manipulation using a functional
approach, and it can greatly simplify many data processing tasks.
○ It enables more concise and readable bulk data operations.
○ It includes a rich set of operations for filtering, mapping, reducing, collecting, and
more, and it allows for easy parallelization, leading to potentially more efficient
code execution.
○ It is one of the key features in modern Java programming that aligns with
functional programming paradigms. We use it extensively here at Ethic.
○ More comprehensive notes are contained in a separate document.
● Python Tuple data type
○ Python has a built-in tuple data type. Python’s tuple is an immutable, ordered
collection of elements that can contain elements of different types.
■ Example: my_tuple = (1, “two”, 3.0)
○ Java does not have built-in support for tuples. At Ethic we use third-party libraries
that provide support for tuples, particularly the Vavr library. We have also written
extensive helper functions around the Vavr tuples.
■ Example declaration: final Tuple2<Integer, Integer> my_tuple
= [Link](1, 2);