.NET vs Java

by David Jeske

There are many substantial differences between .NET and Java. Each has advantages and disadvantages. Here I would like to highlight a few striking features which are uniquely powerful in each.

Java .JAR files

Java JAR files allow you to truly package up an application as a single simple file. In addition to holding the code for your application, JAR files allow you to include other resources, such as images or text resources.

Java WebStart

While this is a very recent addition to Java's capabilities, Java Web Start dramatically demonstrates how easy it can be to install and manage Java software over the internet. It automatically handles downloading, installing, checking for updates, and upgrading software written in Java -- all from a simple link on the web.

All software should be this easy to use.

.NET precompiled assemblies (ngen)

One of the biggest criticisms of Java (and .NET for that matter) is long startup times. Microsoft.NET contains a tool called ngen which allows you to precompile your .NET assemblies (.DLL or .EXE) into the precompiled assembly cache. This eliminates the need to JIT compile this code each time an application is loaded, improving startup times.

As more and more applications run in these environments, it will become increasingly important to enable true shared libraries to reduce memory usage on the machine. ngen allows this because multiple applications can each map and use a common version of the precompiled version of an assembly.

.NET CIL Performance

One of the detractors of JIT environments, even with modern day Ghz CPUs, is performance. The Microsoft.NET CIL environment has some subtle changes which allow it to achieve performance much closer to that of native C++ executables. Those are: Here are some references about good performance in .NET:

C#/.NET foreach / unified type system / Generics

Using Java's basic datatypes in collections is troublesome. It's three times the work of weak-type languages like Python, without any type-safety. Loops are particularly confusing with both "Iterator" and "Enumerator" classes doing nearly the same thing.
  // java collection nastiness
  Hashtable t = new Hashtable();      // Hashtable
  Hashtable t_int = new Hashtable();  // Hashtable

  t.put("foo", new MyObject());
  MyObject o = (MyObject)  t.get("foo");

  t_int.put("bar",new Integer(3));
  int val = ((Integer) t_int.get("bar")).intValue();

  Iterator itr = t.keys();
  while (itr.hasNext()) {
    String n = (String) itr.next();
    // ...
  }

  Enumerator e = t.elements();
  while (e.hasMoreElements()) {
    MyObject o = (MyObject) itr.nextElement();
    // ..
  }

The first version of .NET took two steps. The first one with it's unified type system, solving the manual "int"<->"Integer" conversions which must be done in Java. The second one with the foreach() loop construct to make iterating collections easier.

The next version of C#/.NET will solve the type-coercion and weak-compile-time-checking of untyped collections by adding Generics support. Generics also allows important performance speedups on value-type collections, such as integer keyed hashtables. Current Java and C# implementations of integer keyed hashtables are slowed than script languages like Perl and Python because of the overheard of creating "boxed Integer objects" when interacting with these collections. Generics allows type-specific versions of this code to be compiled, eliminating the "boxed Integer object" creation.

  // C# with new Generics support
  Hashtable t = new Hashtable();
  Hashtable t_int  = new Hashtable();

  t.put("foo", new MyObject());
  MyObject o = t.get("foo");

  t_int.put("bar",3);
  int val = t_int.get("bar");

  foreach (String n in t.keys()) {
    // ...
  }
  foreach (MyObject o in t.elements()) {
    // ...
  }
The next version of Java is rumored to be including Generics support as well. The Java implementation of Generics will not solve the manual boxing required for Java's basic datatypes or the performance problems which result. However, it does have some unique features, including paramaterized types at the method level, type inference for generic methods, and somewhat transparent interfacing with unparamaterized types in Legacy code. [more]