September 12, 2019

Java Primer for Python Developers

I took these notes while ramping up on Java, as I onboarded at Personal Capital in my first Java role since college.

There are large distinctions between the two programming languages, but I’ll try to give the most notable that I encountered–as I approached Java from a Python-heavy background.

Everything is scoped to a class

In Java, every file contains 1 public class definition:

public class Example {
    ...
}

You cannot declare 2 classes in 1 file–and the filename has to match the class’s name.

For example, putting this in 1 file will cause a compilation error:

public class A {}
public class B {}

That doesn’t preclude you from declaring a class within a class (an “inner” class):

public class A {
    public class B {}
}

Or private classes along-side your 1 public class:

public class A {}
private class B {}

This also holds for declaring “top-level” variables–all variables in your program have to be declared as fields on a class or declared within the scope of a class method.

For example, let’s say you want to declare a constant:

In Python you might say:

LOG_LEVEL = "info"

In Java you would say:

public class Configuration {
   public final static String LOG_LEVEL = "info";
}

To further illustrate the difference, let’s say the constant is read and set from an environment variable:

LOG_LEVEL = os.environ.get("LOG_LEVEL")
print(LOG_LEVEL)

In Java, the idiomatic approach would be:

public class Configuration {
    public String logLevel = System.getenv("LOG_LEVEL");

    public static void main(String[] args) {
        System.out.println(getLogLevel());
    }
}

Explicit scopes

public, private, protected are keywords that Java provides to help guide (and enforce) scope of access to variables + methods.

In Python, “private” scoping is indicated by prefixing your variable name with an underscore (“_”), e.g.:

class Example:
    _x = 0
    y = 0

In Java, this is done explictily:

public class Example {
    private int x = 0;
    public int y = 0;
}

I prefer the Python style, simply because it’s cleaner to read.

Dependency injection

Dependency injection (DI) frameworks like Guice and Spring are highly adopted in Java software.

I had not encountered DI in coding Python (but had with AngularJS), so I had some learning to do on this subject in my new job.

A huge benefit of a strongly-typed language like Java over a dynamically-typed language like Python is that type errors cannot happen at runtime.

Using a DI framework in Java manages to introduce a new kind of fatal runtime problem (the “dependency” not found error) which can be highly frustrating and time-consuming.

For example in Spring, there is the famous: NoSuchBeanDefinition exception

The learning curve for DI is not immense, but you will likely encounter DI frameworks with Java and it’s best to be aware.

List comprehensions and generators

Python provides a beautifully intuitive syntax for performing operations over collections (lists, sets, key-value maps).

To illustrate looping over a list:

>> x = [1, 2, 3]
>> x = [i*i for i in x]
>> print(x)
[1, 4, 9]

An equivalent type of syntax was introduced in Java 8 with the concept of “streams” over items in a collection as well as lambda expressions.

To try to be as idiomatic as I can with Java, the equivalent is:

List<Integer> x = Arrays.asList(1, 2, 3);
x = x.stream().map(i -> i*i).collect(Collectors.toList());
System.out.println(x);

Testing

In Python, the unittest library is part of the standard library and provides an XUnit-style framework for writing class-based tests.

In Java, the dominant testing framework is JUnit, which is also XUnit-based.

For all intents and purposes, they are super-similar and you should have very little learning curve coming from Python:

class AdditionTest:
    def test_add_positive(self):
        assert(2, add(1, 1))

To Java:

public class AdditionTest {
    @Test
    public void testAddPositive() {
        assertEquals(2, add(1, 1));
    }
}

Mocking

Like unittest, the unittest.mock is also provided in the Python standard library, and it’s the preferred way to mock your code in tests.

In Java, there are quite a few flavors of mocking libraries, but the main ones are Mockito, JMockit, and EasyMock.

The biggest difference you’ll face with mocking in Java is dealing with how to mock static and final fields/methods.

If you try to mock something final/static then you’ll encounter runtime errors, and the community will tell you it’s a bad practice (which it may well be).

The chainsaw you can reach for in this case is PowerMockito–a chainsaw that you might not previously have needed in Python-land.

Conclusion

The only thing I might add is that Java requires using an IDE.

With Python I somehow managed to survive with Vim as my IDE.

This is not possible with Java, I do not recommend even trying.

If possible, use IntelliJ Ultimate. If not possible, use Eclipse.