Recently someone reached this site through the search phrase, “is java a good first language 2013”, so I felt tempted to answer this question from my own highly subjective point of view. The short answer is no, it’s not. In fact, Java is one of the worst first languages you could pick. In the following I’ll highlight two main issues. One issue, the complexity of Java, will make life more difficult for you immediately, and the other, the danger of developing myopia regarding programming languages and their capabilities, has the potential to hurt you for many years to come and possibly your entire career.
For a beginner it can be exhilarating to make a computer bend to your will. However, the path to reaching even a low level of proficiency is paved with copious amounts of frustration. Writing code demands a level of attention to detail and a degree of logical thinking that is above what the average person could muster. Gaping holes in your logic are par for the course in, say, mainstream media or normal conversations, but a computer is not so forgiving. Just learning to proceed in a clear, logical way is difficult enough for a novice. But not only do you have to learn that. In addition, Java and other “industry-strength” languages burden you with their complexity and will therefore make it more difficult for you to learn programming.
One concept you’ll learn in CS101 is what computer scientists call “types” or “data types”. The declared type indicates how a data has to be interpreted, and determines how it can be manipulated. For instance, an integer with the value 42 is not the same as a string with the value “42”, even though they look the same when printed to the screen. You can multiply an integer by 2, but not a string. On the other hand, you can append another string to a string. All of this is probably not overly exciting. In Java, you have to declare variables with their type. In a more modern language like Python, which has been around for over two decades, you simply initialize the variable since it is dynamically typed. Here is an example if this sounds confusing. [Note: Static typing isn’t necessarily bad. However, the type system of Java doesn’t buy you much, unlike the type inference in Standard ML and other functional languages, but if this is an objection you wanted to raise, then you aren’t a beginner and shouldn’t consider yourself part of the target audience of this article.]
Let’s say you’ve got a list of integers and want to double each entry of the list. If you want to use Java for that, you’ll end up writing a nice little piece of code like this:
package demo; public class RangeDemo { public static void main(String[] args) { int[] myArray = { 1, 2, 3, 4, 5 }; for (int i = 0; i < myArray.length; i++ ) { myArray[i] *= 2; } System.out.println(myArray); } }
If you’ve never seen code before in your life, this might look quite intimidating. You’ve got all this scaffolding, and plenty of keywords which represent concepts you have not encountered yet. You know nothing about packages, or classes. The syntax is baroque. What are all those curly braces about? What are the semicolons good for?
In fact, for a beginner writing something as simple as those few lines of code can pose a significant challenge in Java. This is not because the operations that are involved are so difficult to grasp. It’s basic arithmetic, after all. Instead, the reason is that Java throws so much unnecessary complexity at you. By the way, I’ve hidden an easter egg in that code. Try to run the example for yourself, and you’ll see what I mean. Come on, try it! I’ll wait for you.
Strange, isn’t it? The console gave you an output like “[I@4b71bbc9”. This is the location of the array in memory. To actually print the content of the array, you have to import the Array class, and then convert the array to a string representation:
package demo; import java.util.Arrays; public class RangeDemo { public static void main(String[] args) { int[] myArray = { 1, 2, 3, 4, 5 }; for (int i = 0; i < myArray.length; i++ ) { myArray[i] *= 2; } System.out.println(Arrays.toString(myArray)); } }
As you see, this is a lot of code to do something very simple. Sadly, this approach scales. While your first programs will be a few dozen lines that should be just one or two, your larger programs will be several hundred lines instead of a few dozen, and in even more unfortunate cases several thousand instead of a few hundred. At this point, you’ll have heard of “patterns”, which were developed as a consequence to the deficiencies of the language and are largely superfluous in more advanced languages. [Peter Norvig discusses this problem in greater detail in Design Patterns in Dynamic Languages, but it won’t make much sense for a beginner. Maybe bookmark the link and come back after some months or a year.]
There is also the notion of “boilerplate code”, which is a problem in Java and other equally verbose programming languages. You might think that printing “hello world” should be one or two lines. Not in Java. Or you might think that a common operation like opening a file should be a line or two and consist of specifying the file name and the mode, i.e. whether the file is supposed to be only read or read and written to. In Java this isn’t quite so simple. Here is an example I’ve taken from Hackerrank:
import java.io.*; import java.lang.*; public class Solution { public static void main( String[] args ) { File fileName = new File( "myfile.txt" ); if( !fileName.exists() ) { System.out.println( "this file doesn't exist " ); try { fileName.createNewFile(); FileWriter fileWrite = new FileWriter( fileName ); BufferedWriter bufferedWriter = new BufferedWriter( fileWrite ); //bufferedWriter.write( "write something here " ); bufferedWriter.close(); } catch ( IOException e ) { //catch exception } } else { //System.out.println( "this file exists " ); try { byte[] buffer = new byte[ 100 ]; FileInputStream inputStream = new FileInputStream( fileName ); int readLines = -1; while( ( readLines = inputStream.read( buffer ) ) != -1 ) { //System.out.println( new String( buffer ) ); } inputStream.close(); } catch ( IOException e ) { //catch exception } } } }
Yes, all this just to open and read a file! Also note that the use of the “BufferedWriter” in the first try block constitutes what I’ve once been told was a “pattern”. Now if you look at the try block in the else statement, you may wonder why there is no analogue like a “BufferedReader”. In this example, the file is read as an input stream. Last time I checked, the recommendation was to use “BufferedReader” since it provided better performance when reading large files, but this is nothing you have to worry about in CS101. But let’s not get lost in details. The point I’m trying to make is that code like the one above is, well, utter madness.
By the way, this is the equivalent in Python:
#!/usr/bin/python filename = "myfile.txt" with open( filename ) as f: # file read can happen here # print "file exists" print f.readlines() with open( filename, "w") as f: # print "file write happening here" f.write("write something here ")
Again, the example has been taken from Hackerrank. The pound sign (#) indicates a comment and is not necessarily for program execution. Thus, you’re looking at a total of five relevant lines of source code. Yes, five.
Those were just two random examples, but they hopefully illustrate why choosing Java as a first language is a rather bad idea. I’m proficient to various degrees in about half a dozen languages. However, I don’t think I’ve ever found myself in a situation where I was writing code in, say, Python or Erlang and said to myself, “I wish I could do this in Java instead.” When I have to work in Java, though, I tend to feel reminded of the increased expressiveness of other programming languages.
Instead of Java as a first language, I’d recommend you learn Python instead. Python code can be very clean and readable, and dynamic typing makes it more fun, too. I haven’t given you the equivalent of the very first Java example yet, which was doubling the numbers of an array of integers. The Java code at the beginning of this article can be expressed in Python like this:
my_array = [1, 2, 3, 4, 5] my_array = [ number * 2 for number in my_array ] print my_array
If this is too verbose, you can shorten it a bit:
print [ number * 2 for number in [1, 2, 3, 4, 5] ]
This is what people mean when they say that one line of Python can replace ten lines of Java. As a beginner, you’ll probably find this code easy to understand, even if you’ve never seen code in your life.
Apart from all the unnecessary complexity Java throws at you, there is another aspect I’d like to highlight: programming language myopia. Many people find it very difficult to liberate themselves from the mental models and habits they have acquired in their first programming course. Instead of adopting a beginner mindset again when picking up a different language and learning what it offers, they view everything from the one perspective they know, and happily write Java in Scala or Java in Python or Java in any other language that lets them get away with it. They pronounce that differences between programming languages are “just syntax” and never realize that they don’t make use of more advanced features of the languages they use.
It’s too easy to be complacent when your code seemingly works. Your overly verbose Java in Scala does the job, so why would you bother stretching yourself a little bit? This attitude is common, and you’ll have no problem bumping into people who reject using more powerful languages because of their “weird syntax”. For more on this, read what Paul Graham has to say about Blub programmers. It may come in handy at a nerdy cocktail party. Variations of what Paul Graham calls the Blub Paradox can happen at all levels of competency. People think what they are doing is good enough and don’t make an additional effort. However, it is a missed opportunity if you view a more expressive language from the view of a less expressive one and never familiarize yourself with the possibilities more powerful languages offer.
For a possibly surprising example, let me tell you about one of the MOOCs I sampled earlier this year, MIT’s Introduction to Computer Science and Programming. There are many conveniences in Python, for instance an immediate variable swap. Swapping the content of the variables a and b requires nothing more than writing “a, b = b, a”. On the other hand, in Java and many other programming languages you would have to use a temporary variable and express the same in three lines. Of course, you can write the same three lines in Python and use the temporary variable you’re used to. It works, but it’s considerably less elegant. This is a relatively harmless example. More severe was the introduction to object-oriented programming in that course was taught from a clearly Java-inspired perspective. In Java it is necessary to write so-called getter and setter methods, sometimes called accessor and mutator methods. Yet, this is superfluous in Python, where you have direct access to attributes you want to access or modify. Now, if this happened in a CS course that was taught by MIT, then it’s probably safe to assume that a college freshman who is starting out with Java isn’t immune from that kind of programming language myopia either, so do yourself a favor and learn one or two other programming languages first.
I got here by searching “is java a good first language”. O:
Great post. I think you meant you were doubling the numbers in the list, not squaring them.
You’re right. I just fixed this.
I am learning programming at University, and I find learning Java rather enjoyable. It also helps that Java’s syntax is super similar to C languages, so going from Java to C is pretty painless, syntax wise.
Wouldn’t Golang be a better choice as a first programming language?
Go is arguably a better language than Java, but it is still comparatively low-level. For teaching computational thinking, I would use a more expressive language.
Unfortunately Java is good 🙂 Why? Simply because it is an optimal combination of three things: maintainability (long term projects greatly benefit from it), practicality (it’s much easier and faster to implement features in Java than in any of functional languages, but it’s much more restrictive than dynamic languages, leaving less space for errors during refactorings ) and universality (you can do anything on Java from highly performant servers for big data to desktop applications which work for almost all platforms).
J7 looked a bit vintage in 2010’s that’s true, but release of J8 returns status quo – Java now has all the needed instruments to remain No.1 language for a few years more.
I doubt all three points you mention. By the way, you contradict yourself, but I will leave it as an exercise for you to figure that out.
If I contradict myself, then just point it out 🙂 About your doubts, you are not alone, but I prefer more objective estimations, you can go http://www.tiobe.com/tiobe-index/ or http://githut.info/ just to understand, that Java is on top. Everything you wrote in your post is probably true, but if it was important, Java couldn’t get that high nowadays. But it is there and we have to deal with it. My post is simply a try to explain why it is so.
Read up on “inertia”. Furthermore, TIOBE uses a highly questionable method for estimating the relative popularity of programming languages.
I agree, I think that Java is a pitfall and can cause more problems to someone who’s learning. It’s like recommending someone to run a 10k marathon to someone who’s never even ran a 3k. That being said, I still think that C is a better language to start with as it teaches you the fundamentals.