The End of “Python for Scripts, Java for Systems”
How JBang and Java 21 collapsed the prototype-to-production gap
We all know the joke. To read a file in Python, you type two lines. To read a file in Java, you need a project structure, a pom.xml, a public static void main, three imports, a try-catch block, and a prayer. For a decade, I’ve lived by a simple rule: Java for the Enterprise, Python for the weekend. If I needed to build a bank, I chose Java. If I needed to scrape a website or multiply two matrices, I reached for something lighter without hesitation. The friction of ‘Old Java’ was just too high for quick ideas.
But recently, I realized something that unsettled me. We haven’t been fighting the Java language; we’ve been fighting the Java ceremony. What happens if you strip away the build files, the folder hierarchies, and the boilerplate? I decided to test this. I took some simple Python scripts and rewrote them in Modern Java. The results weren’t just comparable; they were terrifyingly good.
The “Magic Trick”
The reason Python feels like magic isn’t exactly the syntax but the workflow. You open a file, type code, run python script.py, and it works.
Java, historically, has hated this workflow. It demanded you bow down to the “Ceremony”:
Create a directory structure (
src/main/java/com/org...).Write a build file (
pom.xmlorbuild.gradle) with 50 lines of XML/Groovy.Compile.
Run.
If you just wanted to scrape a webpage, you wouldn’t bother. You’d use something a lot lighter.
JBang is a tool that lets you run Java code as a script. No build files. No boilerplate. No directory structure. You can declare dependencies right inside the Java file using a comment. I have written about JBang before
and will spare you all the details and default so the mini introduction here.
Coupled with Java 21, which introduced “Unnamed Classes” (JEP 445), we can finally kill the public class Main { public static void main... } noise.
Here is the new reality:
Create a file:
script.javaAdd a dependency:
//DEPS io.vertx:vertx-web:4.5.1Run it:
jbang script.java
That is it. You now have the power of the JVM with the ease of a bash script. To prove this isn't just theory, I took five common "Python only" tasks and rewrote them in Modern Java.
The Instant Microservice (Flask vs. Vert.x)
Python’s Flask is famous for the 5-line web server. With JBang and Vert.x, Java can now do the same. This script compiles, resolves dependencies, and runs a high-performance Netty server in one go.
The Challenge: Spin up a high-performance HTTP server that serves files from the local directory.
Save this as Server.java and run jbang Server.java.
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.vertx:vertx-web:4.5.1
import io.vertx.core.Vertx;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.StaticHandler;
void main() {
var vertx = Vertx.vertx();
var router = Router.router(vertx);
// Serve static files from the current directory
router.route("/*").handler(StaticHandler.create("."));
vertx.createHttpServer()
.requestHandler(router)
.listen(8080);
System.out.println("Server running on port 8080, serving files from current directory");
}The Java version is technically one line longer than Flask, but it spins up a Netty server capable of handling tens of thousands of concurrent connections. It compiles and runs instantly.
Matrix Math (NumPy vs. ND4J)
One of Python’s strongholds is NumPy. Java’s equivalent is ND4J (part of the DeepLearning4j ecosystem). It brings optimized C++ matrix operations to Java. While Java lacks operator overloading (you can’t do A @ B), the JBang integration removes the “dependency hell” that usually scares people away from Java AI.
Save the following as Multiplication.java and run jbang Multiplication.java.
//DEPS org.nd4j:nd4j-native-platform:1.0.0-M2.1
import org.nd4j.linalg.factory.Nd4j;
void main() {
var A = Nd4j.create(new double[][] { { 1, 2 }, { 3, 4 } });
var B = Nd4j.create(new double[][] { { 5, 6 }, { 7, 8 } });
// Matrix Multiplication
var C = A.mmul(B);
System.out.println(C);
}Java still lacks operator overloading (so we use .mmul() instead of @), but the setup pain is gone. You get C++ speed with Java type safety.
The CLI Tool (Argparse vs. Picocli)
Python scripts are great for CLI tools because of argparse. Java used to require parsing String[] args manually. Picocli is a library that makes Java CLIs actually easier than Python because it uses strong typing and annotations to auto-generate help menus.
Save the following as ParseArgs.java and run jbang ParseArgs.java -n Markus.
//DEPS info.picocli:picocli:4.7.5
import picocli.CommandLine;
import picocli.CommandLine.*;
@Command(name = "greet", mixinStandardHelpOptions = true)
class Greet implements Runnable {
@Option(names = {"-n", "--name"}, description = "Who to greet", defaultValue = "World")
String name;
public void run() {
System.out.printf("Hello, %s!%n", name);
}
void main(String... args) {
new CommandLine(new Greet()).execute(args);
}
}The Java code is structured and strictly typed. If you try to pass a number where a string is expected (or vice versa in more complex tools), Picocli catches it. Python would let it crash at runtime.
High-Concurrency Web Client (AIOHTTP vs. Vert.x Web Client)
Python users love aiohttp or requests for scraping. The Java HttpClient (Java 11+) is good, but Vert.x (built on Netty) is non-blocking by default. It allows you to fire off thousands of requests on a single thread, similar to Python’s asyncio but often with better raw throughput.
Save the following as GrabZen.java and run jbang GrabZen.java.
//DEPS io.vertx:vertx-web-client:4.5.1
import io.vertx.core.Vertx;
import io.vertx.ext.web.client.WebClient;
void main() {
var vertx = Vertx.vertx();
var client = WebClient.create(vertx);
client.get(443, "api.github.com", "/zen")
.ssl(true)
.send()
.onSuccess(res -> System.out.println("Github Zen: " + res.bodyAsString()))
.onFailure(err -> System.err.println("Error: " + err.getMessage()))
.eventually(() -> vertx.close());
}We matched the async capabilities of Python without the Global Interpreter Lock (GIL) holding us back. You get the non-blocking ease of aiohttp with the raw speed of Netty.
Lessons Learned
The exercise of rewriting these scripts taught me something important. We often debate “Language A vs. Language B” based on syntax. We argue about semicolons, whitespace, and brackets. But after rewriting these tools, I realized that syntax was never the real problem.
Here are the three big takeaways from the experiment.
Tooling Matters More Than Syntax
Python didn’t win the last decade of data science and scripting because of significant whitespace. It won because of pip and the REPL. The friction to go from “zero” to “running code” in Python is almost non-existent.
Java lost that ground because of Maven and Gradle. The language itself is fine. But requiring a strict directory structure and a verbose XML configuration file just to print “Hello World” with a library was a fatal flaw for quick tasks. JBang proves that if you fix the tooling, Java becomes just as viable for scripting as Python. The “DX” (Developer Experience) gap is closing fast.
The “Prototype to Production” Cliff is Gone
The biggest risk with Python is the “Rewrite Cliff.” You write a hacked-together script in Python to test an idea. It works. Then you want to put it into production. Suddenly, you need to handle concurrency, type safety, and performance. You often end up rewriting the whole thing in Go or Java.
With Modern Java, that cliff disappears. You can write your prototype as a single-file script using JBang. When it becomes “serious,” you don’t have to rewrite it. You just move that file into a standard Maven project structure. You are scripting in the same language you use for production. That is a massive productivity unlock.
Types are Actually Nice for Scripts
I love dynamic typing for 5-line scripts. I hate it for 500-line scripts. When I was writing the CLI tool in Python, I had to manually check if args.age was an integer. If I forgot, the script would crash halfway through execution.
In the Java version, the compiler caught those errors before I even ran the code. There is a sweet spot where you want the brevity of a script but the safety of a compiled language. JBang hits that sweet spot perfectly. You get the “just run it” feel of bash, but the “it actually works” confidence of Java.
Visualizing the Shift: The Complexity vs. Pain Curve
I wanted to visualize exactly why this shift feels so significant. I plotted Project Scale (x-axis) against Developer Pain (y-axis) to see where the friction really lives.
The results highlight exactly why we have been stuck in the “Python for scripts, Java for systems” mindset for so long and why that mindset is now obsolete.
The Python Trap (Blue Line)
Python starts in “Scripting Bliss.” There is zero friction. You type, you run. But notice the curve as complexity grows. As you add thousands of lines of code, the lack of static typing and the “magic” that made it easy to start begins to work against you. You enter “Maintenance Hell,” where refactoring becomes risky and performance bottlenecks appear.
The Old Java Wall (Grey Line)
This is the “Boilerplate Wall” we all know. The pain starts immediately. You haven’t even written code yet, and you are already fighting with build tools and directory structures. However, notice that the line is flat. Once you pay that initial “tax,” Java scales beautifully. The problem is that for small scripts, the tax is too high to pay.
The Modern Java Sweet Spot (Orange Line)
This is the revelation. By using JBang and Java 21, we bypass the Boilerplate Wall entirely. We start at the same low-friction point as Python. But crucially, because we are still using Java, we don’t suffer the exponential pain curve later on. We get the Scripting Bliss of Python with the scalable reliability of Java. We used to choose languages based on where we wanted the pain to be: at the start (Java) or at the end (Python). Modern Java removes the choice. You can finally have a low-friction start and a high-performance finish.
Summary of the “Modern Java” Stack
For twenty years, the division of labor was clear. You used Python to play, and you used Java to work. You used Python to script, and you used Java to build systems.
That era is over.
With Java 21 and JBang, the barrier to entry has evaporated. You can now wield the power of the JVM, the speed of Netty, and the ecosystem of DeepLearning4j with the same ease as a Python script. You no longer have to choose between developer velocity and runtime performance. You can have both.
Your Homework I don’t want you to just nod along. I want you to try it.
Install JBang (
curl -Ls https://sh.jbang.dev | bash).Copy the code from this article.
Run it.
It will take you less than 60 seconds. And it might just change how you view the next ten years of your career.
Happy coding.




