In the last days and weeks I have read several posts “against” Java and I agree with them in most of their arguments. I think Java is not the best choice for everything and Java shouldn’t be the only language learned at universities.
In this post I’m going to talk about those things that on my opinion Java could be better on. I think sometimes Java is too much verbose. This can be for syntax reasons or for missing methods in the standard API. These are some of the methods I think are missing.
Collections
There is no a direct way to add all values from an array to a collection. You can add all the elements in a collection to other with addAll(Collection<? extends T>
, but you cannot add an array to a collection using just one method. There is no addAll(T[]) method. You can use a trick to avoid having to iterate over the array:
List<String> list = new ArrayList<String>(); String[] array = { "foo", "bar" }; list.addAll(Arrays.asList(array));
But this is not optimal, of course.
Another thing I have had to fight with is why java.util.Properties doesn’t implement Map<String, String> rather than Map<Object, Object>. For example if I have a Map<String, String> and I want to add the content of a Properties object I can’t use the following code:
Map<String, String> map = new HashMap<String, String>(); map.putAll(System.getProperties());
You could do that if Properties had implemented Map<String, String>…
Another thing is converting collections to arrays. You can use the toArray() method, but you have to pass an empty array to make it work.
List<String> list = new ArrayList<String>(); list.add("foo"); list.add("bar"); String[] array = list.toArray(new String[0]);
Input / output
Reading from the standard input has always been hard in Java. There is no System.in.readLine() because System.in is an InputStream. You have to create a BufferedReader to read lines from the standard input. I would love something like Console.ReadLine() (in C#). Well, in Java5 you can use a scanner. But… until Java5 we had to write too much code! This is an echo application example implemented with the new java.util.Scanner class:
Scanner b = new Scanner(System.in);
String line = null;
System.out.println("echo examle, write 'quit' to exit");
while(!"quit".equals(line)) {
line = b.nextLine();
System.out.println(line);
}
System.out.println("bye!");
I don’t know how many times I have needed to write an entire InputStream into an OutputStream. For example when you need to copy a file. I would love a writeTo() method in the InputStream class in order to be able to do something like this:
new FileInputStream("foo.dat").writeTo(new FileOutputStream("bar.dat"));
And also an analog method for readers and writers. The writeTo() method would be overloaded with two optional arguments. First: the length of bytes / characters to read and write (a negative number would mean “all”); and second: the size of the buffer to be used. This is a utility method I use on my classes:
public static void writeTo(InputStream in, OutputStream out, int buffsize, int length) throws IOException {
byte[] buff = new byte[buffsize];
int read = -1;
do {
read = in.read(buff, 0, length < 0 || buff.length < length ? buff.length : length);
if(read == -1) break;
out.write(buff, 0, read);
length -= read;
} while(true);
}
There are other common tasks when using files that you have to implement on your own like:
- Copying files.
- Removing directories recursively.
- Reading a complete text file as a String. This can be dangerous if the file is too large, so the method could have an argument to specify a limit length.
- Reading a complete InputStream or Reader into a String.
- Iterating the lines of a text file more easily. For example in Python you can do the following:
for line in file("FileName.txt"): # Process line
Since years I use CommonsIO for all these tasks but I would like they to be implemented in the standard API.
Swing desktop integration
- I want to be able to open a File with the default installed application. For example I want the user to open the application help that is saved in PDF format with the default installed PDF reader.
- I want to browse a URL in the default browser. For example I want the user to go to the purchasing web page in a shareware application.
- I want to open the default mail composer. For example I want to let the user to send me (as the software developer) an email easily.
At least! We have the destktop API in Java6.
Swing components
- I want a component to let the user to pick up a date in a calendar! This is a must-have in any UI toolkit!
- Why is too complicated to collapse or expand all nodes in a JTree? Well, it can be dangerous depending on the TableModel because nodes in a TableModel are showed on demand. The TableModel could have too many nodes (i.e. files in a file system) or it could have infinite nodes. Maybe it would be useful to add a method in the TableModel interface: boolean canExpandAll(); and then two methods in the JTree class: expandAll() and collapseAll().
Common algorithms
- Where is the support for base64 encoding and decoding? Oh, I found it: import sun.misc.BASE64Encoder…. Wait! this is not the standard API! If you are interested in a JRE-independent implementation use this base64 encoder / decoder licensed under the public domain.
- I would like to be able to do this: Md5.hash(”foo”) or SHA1.hash(”bar”); Why not? And I want it on the standar API!
Enterprise applications
- Writing XML. Which is s the standard way? I want Document.write(…) or Document.toString(). Ok, I know it depends on the W3C DOM API and I also know that there is a Load and Save module for DOM, but this is not included on the standard API on Java. I don’t like W3C DOM for this and other reasons. If I need to use a DOM-like API I prefer JDOM.
- Uploading files in a web application. Why the servlet API is so low level? I have to use Commons FileUpload to be able to read a file from an HTML form!
- Mailing. I love the mail() function in PHP. I would love something more easier than JavaMail for Java.
- For JDBC I would love some utility methods like these:
connection.executeStatement("insert into users (first_name, last_name) values(?, ?)", "foo", "bar"); connection.queryInt("select count(*) from users");Well, you can do these kind of things with Spring Jdbc DAO support and its Jdbc templates.
Proposed syntax changes
In addition to API changes I’m also going to propose some syntax changes. For example I like a lot the syntax for arrays in PHP. Why don’t we could have this in Java:
Map map = new HashMap("first_name" => "foo", "last_name" => "bar");
Or this:
List list = new ArrayList("foo", "bar");
Well, the last one could be possible if ArrayList would have a constructor with varargs.
Another thing I love from some APIs is method chaining. For example I would like things similar to this:
JFrame frame = new JFrame()
.setTitle("title")
.setIconImage(image)
.pack()
.setLocationRelativeTo(null)
.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
.setVisible(true);
Instead of returning “void” return “this” and you will be able to do method chaining. This is not a syntax change, it’s a code convention. But… what if the language by default will return this for any void non-static method? You could do method chaining without implementing it directly.
Conclusions
I like the spirit of Perl: “easy things easy but hard things possible“. And I think in Java a better work could be done. Without considering the proposed syntax changes, hoy many lines of code are required to implement all those functionality? Not too many I think. I don’t want all the Apache Commons APIs inside the standard library. I know that the standard API is too big in some cases. But I think there are missing things that would be very useful and easy to implement. Too many times Java developers have to take a look to the Java Developers Almanac to find what’s the easiest or best way to achieve a common task. Nevertheless I have also to say that Java6 has introduced good API changes. That’s good news.
Talking about the language syntax an excellent work has been done in Java 5: varargs, foreach, generics and outboxing and inboxing. Those changes have done Java less verbose.
On balance, Java is better in each new version, but Java could be better.