C# vs Java Part 1: The Languages (Continued)
Continued from C# vs Java Part 1: The Languages
Primitive Types and Boxing
There are a few subtle differences here that can really throw a programmer off. I think the best way to describe this section is by examples.
In C# this is valid
In Java it looks like this
Because both languages can autobox, I expect that I can use a primitive type like an object. The C# syntax seems more natural to me. I don't want to have to think about Integer vs int. Although a programmer should be aware about boxing, for the most part it should seem transparent. Although, sometimes it is too transparent. Take a look at this innocent looking Java code.
If this code throws a null pointer exception, what can you assume? Ok, now what if I told you myObject is not null? Confused a bit? Here is the strange part. If isFantastic returns a Boolean instead of a boolean it will be automatically unboxed into a boolean. If isFantastic returns a Boolean with a value of null, and it tries to unbox it, the result will be a null pointer exception. The compiler is automatically doing this for you.
This happens to be the syntax that you must use for C#. Is this a bad thing or a good thing? There are arguments either way, but if you have been bit by this automatic unboxing null pointer, you would probably say it was bad.
One final word on primitives. C# language allows a nullable primitive type by using a ? before the variable declaration. So, you can declare a primitive type which is null by typing int? myNullableInt. Whether this is good or bad, I am not completely sold on. It is very useful when you use it properly to eliminate repetitive code, but in general nulls are bad. Nulls create extra complexity and should be avoided if at all possible.
The handling of generics between C# and Java is pretty transparent at a surface level. I would say that when I am writing Java code vs C#, I don't really think about the differences in generics.
Basically Java uses type erasure, and C# includes generics support in the IL code that is generated. Translation: Java compiler erases your generic types and replaces them with casts. C# includes in the generic types in the byte code that runs inside the Common Language Runtime (CLR).
The easiest way to demonstrate the differences is with these code snippets, which I stole from a very informative post on generics in C# and Java.
Contrast this to C# generics implementation which allows these things
A few times working in Java I have wanted to know type of the generic parameter, but in general I haven't seen the type erasure of Java pose much of a problem. So why did Java chose to implement generics as erasures? To maintain backwards compatibility with the JVM. By not changing the structure of the .class files compatibility is maintained.
There is only one major difference in exception handling between C# and Java. Java contains the notion of checked exceptions, which are basically exceptions that must be handled by the caller of that code. In Java you can declare “throws ExceptionType” in the method declaration, and any callers of that method must somehow handle that exception. This seemed like a good idea, but in general really tends to be an annoyance more than anything. I have seen a large amount of Java code where the programmer simply declares any empty catch block and “eats” the exception in order to make the code compile, because he/she is required to catch a checked exception. Checked exceptions also tend to break encapsulation as changes to internal implementations are propagated upwards and can break the caller.
There is also a small difference in finally blocks. In Java a finally block can contain a return or break statement, in C# it cannot. The net effect of this is that you can have some strange Java code that returns in the method and in the finally block. C# also does not process the finally block code when an uncaught exception is thrown, (looks like I was wrong here. The CLI standard seems to be conflicting on this issue. In 220.127.116.11 Overview of exception handling, it indicates that when there is an uncaught exception the finally block is not called. When I tested this out with real code, the finally block was indeed called), while Java will process the finally block. To make up for this C# uses the IDisposable interface with a using statement to allow for clean up when objects go out of scope.
Syntactic Sugar and Other Niceties
This is the part from a language perspective where Java really takes a pounding. C# has been implementing many language level features that make writing C# code very easy and nice.
LINQ – this feature allows writing code that looks more like a SQL query. This is best demonstrated with an example.
This “magic” is actually equivalent to:
The best thing about LINQ is it allows full intellisense support, so when you type “s.” it auto-suggests all the methods available on a String.
Extension Methods – basically this allows the creation of static methods that look like they are part of the class they extend. LINQ uses this feature to create the simple syntax and allow any type that implements IEnumerable to gain all the abilities that are provided in the LINQ namespace like the Where or OrderBy method.
Properties – C# allows a programmer to not have to create getter and setter methods. In addition, properties can be specified without even declaring the private member variable in the class. A default is created and can still be later replaced with a user defined implementation so it does not violate encapsulation.
Operator Overloading – Specifically indexers. It is nice to have a dictionary that you can put things in with dictionary[“name”] = value as opposed to dictionary.put(“name”) = value.
Anonymous Types and Var – C# will allow a code to create a new type inline with properties automatically created. This is very useful for reducing large amounts of code where needed. Here is an example:
You can see how with anonymous types and the var keyword, (which is still statically typed but allows for the compiler to specify the type instead of the programmer), we can create a type which we only need for a brief period of time.
?? – the null-coalescing operator in C# is useful for trimming down code that would normally have an if null do this/else copy value.
As I said at the beginning of this section, C# kind of pounds Java into the ground here as far as language features that are really just ease-of-use or syntactic sugar. Java does have one syntactic sugar feature I can think of.
Static imports – With Java you can declare
import static java.lang.Math.PI;
This import statement will allow the use of the constant PI anywhere in the class file as if it were locally declared.
From a language standpoint I have to admit that I do clearly prefer C# over Java. I think it is very hard to objectively compare Java and C# and pick Java purely from a language perspective. In the other parts of my series I will cover other areas where Java has more advantages. I'm not against Java, I use it almost everyday, but from a perspective of language design, it has been left behind in the dust. Microsoft seemed to make the C# language design adopt to the ease-of-use of the programmer. I look forward to seeing how Java advances to catch up with some of these C# features and make the language experience better.
What do you think? Do you think I have fairly portrayed both languages from a developer perspective?