|
We’re pleased to welcome our guest blogger, Nikos Vaggalis. Nikos is a journalist at i-programmer and a seasoned software engineer with extensive hands-on experience across a wide range of technologies. With a career that bridges technical journalism and real-world software development, he brings a uniquely informed perspective - grounded in both industry practice and analytical insight. You can explore more of Nikos’ published work in this collection of his articles. |
Python. Even if you close your eyes and try to ignore it, you really can’t; it’s everywhere, especially in the AI and Data Science fields. Therefore, it has become a necessity to get to know it, even if you’re a Java developer enjoying its rich and large language ecosystem. Despite the fact that lately Java has been powered up with great AI libraries like LangChain4j, which make it easy to build AI-powered applications, in order to tap into the full, unconstrained pool of AI capabilities, you still need to go to Python.
Of course, to use Python for AI and other advanced use cases, you have to first go through the basics. But no worries, as help is on the way. I had the privilege of becoming a beta tester of Geekuni’s Python Essentials, a brand-new course for intermediate-level programmers who know how to program in a different programming language but are new to Python.
Therefore, this tutorial is based on the course and works by converting a few but crucial selected excerpts from Python to Java. As such, it is addressed to programmers who come from a Java background and want to learn Python, but it works the other way too, that is, for Pythonistas looking at Java. So let’s begin!
In Python, indentation is meaningful
For most languages this is what developers use to help other
developers (or themselves in 6 months) easily identify sections of
code. In the case of Python, indentation actually
defines compound statements in the
way that { curly braces } do for languages like C:
if (x > 0) {
printf("x is positive\n");
printf("x squared is %d\n", x * x);
}
and begin and end do for Pascal:
if x > 0 then
begin
writeln('x is positive');
writeln('x squared is ', x * x);
end;
In Python an if statement looks like:
if x > 0:
print('x is positive')
print('x squared is', x**2)
print('We are out of the if statement now')
In Java of course you use braces.
Polymorphism with strings, and introducing the REPL
We’ll find out the various ways of representing strings by using Python’s REPL (Read-Eval-Print Loop) as a hands-on tool for learning these concepts interactively.
Just open a terminal and run python3 at the command-line.
$ python3
You can then type things at the prompt, press ENTER and see any output on the following line. For example:
>>> name = "Zachary"
>>> print("Hello, " + name)
Hello, Zachary
In summary: it Reads what you typed; Evaluates that string (which
means, it runs it as a Python command); Prints any output (there
was only output in the case of the print statement in this example);
and Loops back to reading the next line you type.
Now you can use the REPL to experiment with the two separate concepts we’re covering here. The first is polymorphism - where we see an operator (or function) behaving differently depending on its arguments. For example:
>>> print(2 + 3)
5
>>> print('foo' + 'bar')
foobar
In the first case it’s adding the arguments, and in the second, it’s concatenating them. The action of the operator is determined by the types of its arguments.
Now, look at the * operator between numbers and strings.
For example:
>>> print(2 * 3);
6
>>> print("1" * 5);
11111
Java Equivalent
In Java you don’t normally have a REPL because it is a compiled language… or can you? Yes you can, with JBang and its JShell scripting. JShell, Java’s Read-Eval-Print-Loop (REPL) tool (available since JDK 9), allows programmers to quickly test code snippets, explore APIs, and incrementally construct code, providing immediate feedback.
You can download and install Jbang, or you can upload it straight into your browser through the “JBang powered Jupyter Environment”. No JDK install. No account. No IDE. Just head over to TryJbang which we’re going to use for running our Java code as painlessly as possible.
Here’s the equivalent Java code - paste each block
into the JBang editor and click run.
String name = "Zachary";
System.out.println("Hello, " + name );
2 + 3;
"foo" + "bar";
2 * 3;
System.out.println("1".repeat(5));
You’ll notice straight away that in Java you have to declare your
variables’ types, such as String name=, which starts life as a
String and dies as a String. In contrast, Python is dynamically
typed and a variable can be a String or a Number or another data
type.
Also notice Python’s string repetition example of:
print("1" * 5);
which in Java ends up as:
System.out.println("1".repeat(5));
That is because Java does not overload the * operator for string
repetition (unlike Python), requiring the String.repeat() method
for this functionality.
Functions
In this exercise we experiment with implementing a function in Python.
As mentioned earlier, indentation defines compound statements in the way that curly braces do so in languages like C. For example - a one line compound statement:
def square(n):
return n ** 2
>>> square(3)
9
There are three compound statements in the following example - the
if block, the else block and also the def block which contains them:
def is_even(n):
if n % 2:
print(f"Sorry, {n} is odd")
return False
else:
print(f"Yay! {n} is even")
return True
>>> is_even(1)
Sorry, 1 is odd
False
>>> is_even(2)
Yay! 2 is even
True
Here’s an example of a recursive function which calls itself:
import math
def num_squares(n):
"""Return the number of squares up to, and including, n
"""
if n == 1:
return 0
return num_squares(n-1) + (
1 if math.sqrt(n).is_integer() else 0
)
>>> num_squares(9)
2
Java Equivalent
In Java, the first example would be implemented as a method within
a class, specifying int as the parameter type and the return type:
public class FunctionConversion {
public static int square(int n) {
return n * n;
}
public static void main(String[] args) {
int result = square(3);
System.out.println(result); // Output: 9
}
}
FunctionConversion.main(null);
The second example. In Java, conditional logic uses parentheses
around the condition and { curly braces } to delimit the code block
for the if and else statements, while output is handled using
System.out.println():
public class FunctionConversion {
public static boolean isEven(int n) {
// In Python:
// - 'if n % 2:' is true if the remainder is non-zero
if (n % 2 != 0) {
System.out.println("Sorry, " + n + " is odd");
return false;
} else {
System.out.println("Yay! " + n + " is even");
return true;
}
}
public static void main(String[] args) {
isEven(3);
// Output: Sorry, 3 is odd
isEven(2);
// Output: Yay! 2 is even
}
}
FunctionConversion.main(null);
Third example with recursion. In Java, you use Math.sqrt() to
calculate the square root. To check if the result is an integer,
you can compare the value to its mathematical floor (Math.floor).
import java.lang.Math;
public class FunctionConversion {
public static int numSquares(int n) {
if (n == 1) {
return 0;
}
double root = Math.sqrt(n);
// Determine if the root is an integer
// In Python: 'is_integer()'
int addValue = (root == Math.floor(root)) ? 1 : 0;
// Recursive call
return numSquares(n - 1) + addValue;
}
public static void main(String[] args) {
int result = numSquares(9);
System.out.println(result); // Output: 2
}
}
FunctionConversion.main(null);
Looking at the Python and Java examples side by side, you can’t help but think that Java’s solutions are more verbose than Python’s.
Making a list with the range function
In this exercise we learn about Python’s range class and how we can use it to make a list.
Let’s start by creating a range object:
>>> range(10)
range(0, 10)
This object represents the integers matching x: 0 <= x < 10, namely 0, 1, ... 9.
But how do you get a list of the actual numbers?
nums = []
for x in range(10):
nums.append(x)
>>> nums
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
The code above introduced you to Python’s append method of a list. It works, but it’s a bit clunky.
Happily, this can be done in one line using the list constructor which takes (in this case) the range object as an argument and returns a list of its elements.
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Java Equivalent
In Java, the first example requires defining a for loop with explicit initialization, termination condition, and increment, and using a generic ArrayList to hold the resulting numbers.
import java.util.ArrayList;
import java.util.List;
public class RangeConversion {
public static void main(String[] args) {
// In Python: nums = []
List<Integer> nums = new ArrayList<>();
// In Python: range(10)
for (int x = 0; x < 10; x++) {
// In Python: .append(x))
nums.add(x);
}
// Print the result to the console
System.out.println(nums);
}
}
RangeConversion.main(null);
Or in modern Java, the second example of Python’s list(range(10))
becomes:
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class RangeConversion {
public static void main(String[] args) {
// Creates a List<Integer> of 0 through to 9
List<Integer> list = IntStream.range(0, 10)
.boxed()
.collect(Collectors.toList());
System.out.println(list);
}
}
RangeConversion.main(null);
Lambdas (of course)
In this exercise we learn how to use lambda functions, a special type of function which is more concise for simple tasks.
First of all, here’s an example of a lambda function which takes a
variable x, and returns x + 1:
lambda x: x + 1
and here’s the same function being called:
>>> (lambda x: x + 1)(2)
3
And this is the same function being assigned to a variable, and then called:
>>> f = lambda x: x + 1
>>> f(2)
3
When you run it like that, you won’t be surprised that the lambda
function with the code lambda x: x + 1 has the same functionality
as the function:
def increment(x):
return x + 1
with the main difference to the caller being the name:
>>> f.__name__
'<lambda>'
>>> increment.__name__
'increment'
The main difference between writing a lambda to a function is that a lambda can only contain a single expression. What’s an expression?
For the statement:
x = 2*(3 + 5)
2*(3 + 5) is the expression.
Python’s lambdas use the programming pattern which comes from lambda calculus - namely functional programming.
What’s functional programming? Unlike procedural programming, where a block of code is a sequence of statements, including assignments which are creating variables or changing their values:
x = 1
y = 2
x += y
code in functional programming is just an expression - the code you
can see on the right hand side of the = assignment operator.
Java Equivalent
The Python lambda function conversion in Java is achieved using Lambda Expressions, a feature introduced in Java 8 to support functional programming. In Java, a lambda expression is a concise way to create an instance of a functional interface (an interface with exactly one abstract method).
So this requires defining a functional interface to serve as the
target type for the lambda. We can define a simple interface, or
use a built-in one like IntUnaryOperator (for operations on a single
integer operand that return an integer result):
import java.util.function.IntUnaryOperator;
public class LambdaConversion {
public static void main(String[] args) {
// In Python: f = lambda x: x + 1
IntUnaryOperator increment = (x) -> x + 1;
// In Python: (lambda x: x + 1)(2)
int result = increment.applyAsInt(2);
System.out.println(result); // Output: 3
}
}
LambdaConversion.main(null)
Key Differences and Java Concepts:
-
Context: Java code must reside within a class.
-
Anonymous Nature: Just like Python’s lambda, the Java lambda expression itself is an anonymous method, but it must be assigned to an instance of a functional interface (
IntUnaryOperatorin this case). -
Return Type: In both Python and Java, if the body of the lambda is a single expression, the result of that expression is implicitly returned without needing a return keyword.
Finally - the map operator
Our final example will demonstrate functional programming in action by building on the Lambdas section above.
The map operator takes two arguments - a function and an iterable, and returns an iterator whose elements are the result of applying the function to the elements of the iterable.
In this exercise we’re playing with the capitalize method of the string class:
>>> 'please check for typos!'.capitalize()
'Please check for typos!'
Here’s a function which takes a string and returns the capitalised version of it:
def cap(word):
return word.capitalize()
Now we can use map to apply this function to a list of words:
>>> uc_words = map(cap, ['this', 'is', 'a', 'test'])
>>> list(uc_words)
['This', 'Is', 'A', 'Test']
Note that the function can also be a lambda:
>>> uc_words = map(
... lambda w: w.capitalize(), ['this', 'is', 'a', 'test']
... )
>>> list(uc_words)
['This', 'Is', 'A', 'Test']
The Python map() function converts easily to Java using Streams and
Lambda Expressions.
Java Equivalent
In Java the functionality of applying a function to every element
of an iterable and collecting the results is typically accomplished
using the stream().map().collect() pipeline.
So the Java Equivalent of the first example would use the Stream API to perform the transformation:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MapConversion {
// Define the capitalization logic as a dedicated method
// (or use a lambda directly)
// Note: Java's standard capitalize methods
// typically handle the first letter only.
// Mimicking the behavior of Python's .capitalize().
public static String cap(String word) {
if (word == null || word.isEmpty()) {
return word;
}
// In Python: word.capitalize()
// Capitalize first letter, lowercase the rest
return word.substring(0, 1).toUpperCase()
+ word.substring(1).toLowerCase();
}
public static void main(String[] args) {
List<String> words = Arrays.asList(
"this", "is", "a", "test"
);
// 1. Create a Stream from the list.
// 2. Use the map to apply 'cap' to each element.
// 3. Use Collectors.toList() to generate a List.
List<String> ucWords = words.stream()
.map(MapConversion::cap)
.collect(Collectors.toList());
System.out.println(ucWords);
}
}
MapConversion.main(null) // Output: [This, Is, A, Test]
Now using the same Lambda Expressions, which Java can use directly in the map operation:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class LambdaMapConversion {
public static String capitalizeWord(String w) {
// In Python: w.capitalize()
// Capitalize first letter, lowercase the rest
if (w == null || w.isEmpty()) return w;
return w.substring(0, 1).toUpperCase()
+ w.substring(1).toLowerCase();
}
public static void main(String[] args) {
List<String> words = Arrays.asList(
"this", "is", "a", "test"
);
// The lambda w -> capitalizeWord(w) is the function,
// is the functional interface required by stream.map()
List<String> ucWords = words.stream()
.map(w -> capitalizeWord(w))
.collect(Collectors.toList());
System.out.println(ucWords);
}
}
LambdaMapConversion.main(null) // Output: [This, Is, A, Test]
The End
So in the end, which code is better? Python or Java? I’ll leave the
answer up to you. But before answering, take into consideration
that with jbang we simplified the syntax of the Java code which
saved a few lines and made it cleaner. We also didn’t need to set
up a JDK or an IDE on our PC. This workflow modernizes Java and
brings it up to par with the facilities other (even dynamic languages)
like Python enjoy.
This caps the tutorial. As already mentioned, all the Python examples used come from Geekuni’s Python Essentials course and represent just a fraction of the available material, material which encompasses all aspects of the language.

No comments:
Post a Comment