| /00 /01 /02 /03 /04 /05 /06 /07 /all |
Java vs Python
Being fed up with all the Java job ads all around and none for Python, I wanted to do something about it. So here it is, yet another article focused on Java-Python comparison, with examples included. Each lesson contains a simple real-life problem, Java solution and, for the sake of comparison, a Python code equivalent.
table of contents
Lesson 1: The Joy of System.out.println()-ing
Lesson 2: Inviting StreamReader family to dinner
Lesson 3: My debug output, your nightmare
Lesson 4: Overloading the trouble
Lesson 5: Pointer madness
Lesson 6: String rhapsody
Lesson 7: The Zen
related
http://paulgraham.com/pypar.html, The Python Paradox
http://dirtsimple.org/2004/12/python-is-not-java.html or how your prior exposure to Java can produce negative side-effects
and many others
| /00 /01 /02 /03 /04 /05 /06 /07 /all |
Lesson 1: The Joy of System.out.println()-ing
Starting with the simplest (hello-world-look-alike) program, this is it: a program that outputs one single line.
1 // java code
2 class javaprog
3 {
4 public static void main(String args[])
5 {
6 System.out.println("I am sys.out.printlning, yay.");
7 }
8 }
Not too bad, you might say. Well, comparing to the following code it is, quite bad:
1 # python code
2 print "I am printing, yay."
Python is simply about saying "get me an orange" when you need one, and not having to tell them a lot of other irrelevant stuff, like "welcome, this is Earth" or "you are free to breathe while you walk" or "an orange is actually World.fruit.orange"...
More of The Joy
Ok, printing static lines is no fun, so what happens when some variables get involved?
Let's say we want to format output of an int, float with 2 decimal places, and double with 4 decimal places:
1 // java code
2 import java.text.*;
3
4 class javaprog
5 {
6 private static int x = 1;
7 private static float y = (float) 0.12345;
8 private static double z = 100.0/3.0;
9
10 private static DecimalFormat df1 = new DecimalFormat("###.##");
11 private static DecimalFormat df2 = new DecimalFormat("###.####");
12
13 public static void main(String args[])
14 {
15 System.out.println("x = " + x + "; y = " + df1.format(y) + "; z = " + df2.format(z));
16 }
17 }
In Java everything has to be declared first in order to be initialized second, to be (optionally) used later. This so-called hard-typing might be a good thing in some cases, although it's not clear which those cases are. What is clear is that Java lacks clarity, comparing to the alternative:
1 # python code
2 x, y, z = 1, 0.12345, 100/3.0
3 print "x = %d; y = %.2f; z = %.4f" % (x, y, z)
Python takes advantage of soft-typing, resulting in clean, flexible code. It also has c's printf() functionality builtin.
| /00 /01 /02 /03 /04 /05 /06 /07 /all |
Lesson 2: Inviting StreamReader family to dinner
There are times, when you ask the user to do something else besides clicking, like maybe entering a number:
1 // java code
2 import java.util.*;
3 import java.io.*;
4
5 class javaprog
6 {
7 private static double x = 0;
8
9 public static void main(String args[])
10 {
11 InputStreamReader isr = new InputStreamReader(System.in);
12 BufferedReader br = new BufferedReader(isr);
13 StringTokenizer st;
14
15 boolean foo = false;
16
17 try
18 {
19 st = new StringTokenizer(br.readLine());
20 x = new Double(st.nextToken()).doubleValue();
21 }
22 catch(Exception e)
23 {
24 System.out.println("Foo.");
25 foo = true;
26 }
27
28 if (! foo)
29 {
30 System.out.println("x = " + x);
31 }
32 }
33 }
It may not look like it, but all that this app actually does is:
- read the number from user input
- print it, or "foo" if error occured
If you're new to Python, before reading any further, take a deep breath.
1 # python code
2 import sys
3
4 try:
5 x = float(sys.stdin.readline())
6 except:
7 print "foo"
8 else:
9 print "x =", x
This lesson tried to demonstrate the general trends: Python's natural simplicity and Java's unnecessary complexity.
| /00 /01 /02 /03 /04 /05 /06 /07 /all |
Lesson 3: My debug output, your nightmare
It's generally a good thing to show tracebacks, but everything's got it's limit...
Here we try to create a double value "foo", let's see what happens.
1 // java code
2 class javaprog
3 {
4 public static void main(String args[]) throws Exception
5 {
6 double x = new Double("foo").doubleValue();
7 }
8 }
This is the output:
java.lang.NumberFormatException: foo at java.lang.Double.valueOf0 (Double.java) at java.lang.Double.valueOf (Double.java:146) at java.lang.Double.<init> (Double.java:48) at javaprog.main (04_debug.java:8)
Python version:
1 # python code
2 x = float("foo")
And the output:
Traceback (most recent call last):
File "04_debug.py", line 1, in ?
x = float("foo")
ValueError: invalid literal for float(): fooIt's true: this topic is a matter of personal opinion; but in general, Python has better traceback output.
| /00 /01 /02 /03 /04 /05 /06 /07 /all |
Lesson 4: Overloading the trouble
Suppose we need a simple class Planet for the planets in our solar system.
The planets have two interesting properties:
- radius
- gravity
Our class constructor must allow specifying both, or only one of the properties, when creating new planets.
1 // java code
2
3 class Planet
4 {
5 protected double radius, gravity;
6
7 public Planet(double radius, double gravity)
8 {
9 this.radius = radius;
10 this.gravity = gravity;
11 }
12 public Planet(double radius)
13 {
14 this.radius = radius;
15 this.gravity = 9.81;
16 }
17 public Planet()
18 {
19 this.radius = 6378.1;
20 this.gravity = 9.81;
21 }
22 }
23
24 class javaprog
25 {
26 public static void main(String args[]) throws Exception
27 {
28 Planet jupiter = new Planet(71492.1, 23.12);
29 Planet venus = new Planet(6052.8);
30 Planet earth = new Planet();
31 }
32 }
Java solution is again far from being elegant or effective, mostly because of constructor overloading (multiple procedures doing basically the same thing).
1 # python code
2
3 class Planet:
4 def __init__(self, radius=6378.1, gravity=9.81):
5 self.radius = radius
6 self.gravity = gravity
7
8 jupiter = Planet(71492.1, 23.12)
9 venus = Planet(6052.8)
10 earth = Planet()
11
12 # not possible in java
13 pluto = Planet(gravity=0.58)
Python code is not just 3-times more readable, maintainable and flexible, Python is also more powerful by allowing you to specify only gravity (without radius). Speaking in terms of Java, this is not even possible.
| /00 /01 /02 /03 /04 /05 /06 /07 /all |
Lesson 5: Pointer madness
Pointers are a way to access variables by referrence, rather than accessing them by value. C has pointer functionality, Python usually doesn't need it, Java lacks it.
Let's do some math. Mission objectives:
Write a function angle_distance(), which
takes two points as a parameter,
returns angle and distance between them,
angle must be in degrees.
- Write a demo program for
points p1 = [0,0] and p2 = [1,1],
print out angle and distance, with 2 decimal places
The source follows, C first.
1 //C code
2
3 #include <math.h>
4
5 void angle_distance(double p1[2], double p2[2], double* a, double* d)
6 {
7 // calc delta x,y
8 double dx = p2[0] - p1[0];
9 double dy = p2[1] - p1[1];
10
11 // set angle
12 *a = atan2(dy, dx);
13
14 // convert to degrees
15 *a = (*a)/M_PI * 180.0;
16
17 // set distance
18 *d = sqrt(dx*dx + dy*dy);
19 }
20
21 int main()
22 {
23 double a,d;
24 double p1[] = {0,0};
25 double p2[] = {1,1};
26
27 angle_distance(p1, p2, &a, &d);
28
29 printf("angle = %.0f, distance = %.2f\n", a, d);
30
31 return 0;
32 }
33 //output: angle = 45, distance = 1.41
Next, Python.
1 #python code
2
3 from math import degrees, atan2 as atan
4
5 def angle_distance(p1, p2):
6
7 # calc delta x,y
8 dx, dy = [n-m for m,n in zip(p1,p2)]
9
10 # calc angle (arcus tangens)
11 a = atan(dy, dx)
12
13 # calc distance (Pythagoras)
14 d = (dx**2 + dy**2)**0.5
15
16 return degrees(a), d
17
18
19 a,d = angle_distance([0,0], [1,1])
20
21 print "angle = %d, distance = %.2f" % (a,d)
22 #output: angle = 45, distance = 1.41
And Java.
1 //java code
2
3 import java.lang.Math;
4 import java.text.*;
5
6 class myAngleDistanceClass
7 {
8 int a;
9 double d;
10 }
11
12 class javaprog
13 {
14 public static myAngleDistanceClass angle_distance(double p1[], double p2[])
15 {
16 myAngleDistanceClass myAD = new myAngleDistanceClass();
17
18 // calc delta x,y
19 double dx = p2[0] - p1[0];
20 double dy = p2[1] - p1[1];
21
22 // set angle
23 myAD.a = (int) Math.toDegrees(Math.atan2(dy, dx));
24
25 // set distance
26 myAD.d = Math.sqrt(dx*dx + dy*dy);
27
28 return myAD;
29 }
30
31 public static void main(String args[])
32 {
33 double[] p1 = {0,0};
34 double[] p2 = {1,1};
35
36 myAngleDistanceClass angleDistance;
37
38 angleDistance = angle_distance(p1, p2);
39
40 DecimalFormat df = new DecimalFormat("###.##");
41 System.out.println("angle = " + angleDistance.a + ", distance = " + df.format(angleDistance.d));
42 }
43 }
44 //output: angle = 45, distance = 1,41
C is a great language for specific tasks, tasks like system programming or anywhere where program execution speed is the primary concern.
Java has a syntax very similar to C, yet the code we got is quite different. Because of Java's lack of pointers, we had to create a whole new class to achieve the same functionality. So each time angle_distance() is called, a new instance of that class is created and returned.
Python code is the usual minimal-effort-to-get-the-job-done, comments in the code are not even necessary. It is not a rare case that Python programs are 2-3 times shorter than equivalent Java programs.
| /00 /01 /02 /03 /04 /05 /06 /07 /all |
Lesson 6: String rhapsody
multi-line strings
- strings that just won't fit in one single line
1 System.out.print("\n" +
2 "<html>\n" +
3 " <head>\n" +
4 " <title>This is java.</title>\n" +
5 " </head>\n" +
6 " <body>\n" +
7 " Messy and hard to read.\n" +
8 " </body>\n" +
9 "</html>\n";
1 print """
2 <html>
3 <head>
4 <title>This is python.</title>
5 </head>
6 <body>
7 Clean, simple, easy to read.
8 </body>
9 </html>
10 """
string comparison
- testing equality of two strings is not always easy
1 // java
2 String foo = "foo";
3 String bar = "bar";
4 if (foo.equals(bar)) { System.out.println("foo equals bar"); }
1 # python
2 foo = "foo"
3 bar = "bar"
4 if foo == bar:
5 print "foo equals bar"
Strings can be compared in Python just like anything else, but not so simple in Java: String objects in Java have to be compared using .equals().
These are two out of many more examples found out in the wild, showing that, actually, string manipulation in Java sucks.
| /00 /01 /02 /03 /04 /05 /06 /07 /all |
And for the end, a little philosophy.
The Zen of Python, by Tim Peters
- Beautiful is better than ugly.
- Explicit is better than implicit.
- Simple is better than complex.
- Complex is better than complicated.
- Flat is better than nested.
- Sparse is better than dense.
- Readability counts.
- Special cases aren't special enough to break the rules.
- Although practicality beats purity.
- Errors should never pass silently.
- Unless explicitly silenced.
- In the face of ambiguity, refuse the temptation to guess.
- There should be one-- and preferably only one --obvious way to do it.
- Although that way may not be obvious at first unless you're Dutch.
- Now is better than never.
- Although never is often better than *right* now.
- If the implementation is hard to explain, it's a bad idea.
- If the implementation is easy to explain, it may be a good idea.
- Namespaces are one honking great idea -- let's do more of those!
The Zen of Java, not to be taken too seriously
Beautiful is better than ugly, with System.out.println(), InputStreamReader, method overloading and other features being unfortunate exceptions.
- Explicit is better than implicit, but feel free to obfuscate the code a little, should you feel the urge to do so.
- Simple is almost never better than complex: good applications are always complex, period.
Complicated is even better: you get more money for doing the hard work.
Flat is better than nested, but that's just utopist's saying. In practice you will fail, so don't bother.
Sparse is better than dense, unless you've got a totallySuperAwesome_40CharactersLongName for your new class, and want everyone to see it.
Readability counts.. sheep before it falls asleep.
Special cases aren't special enough to break the rules. (that's why we don't have them).
Although practicality beats purity. (forget multi-line strings that's not what I'm talking about).
- Errors should never pass silently. They have to be all over the screen, no matter the size.
Unless explicitly silenced. That's when you start throwing Exceptions all over the place.
- In the face of ambiguity, refuse the temptation to guess. Use XML and you'll be fine.
- There should be none-- and preferably less than one --obvious way to do it.
- Although the one obvious way may appear sometimes, for no particular reason.
Now is better than never. And don't ask me what a lambda function is. It's evil and therefore not supported in Java.
- Although never is often better than *right* now. But hey, you're the Java drone. Get to work, *right* now.
- If the implementation is hard to explain, try harder and you'll get it, eventually.
- If the implementation is easy to explain, you are looking at the wrong source. Open the appropiate .java file, there's the implementation in question.
- Namespaces are one honking great idea -- wish we had implemented them the proper way!
This Java Zen stuff is (obviously) meant as a joke, although there might be some truth in there.
Or maybe I'm looking at it from a wrong prospective...
Anyway, this is the end, I hope it was at least a little entertaining, if not informative.