I have been long contemplating this post, because I think it is a very important topic, but I have also lamented writing it do to the controversial nature of the subject and fearing that I would not be as accurate in my portrayal as deserved. Nevertheless, I am going to attempt to cover selective parts of this subject in a several part post series, C# vs Java.
A little bit of preamble before I begin getting into the language differences:
- When I am comparing C# to Java, I am also comparing the platforms. .NET framework and the CLR are as much part of C# as the JVM and Java EE stack are part of Java.
- I am covering this topic from the perspective of a developer and architect working with both of these technologies. The perspective is from my personal perspective, from my experience. I do not see it fit to rehash much of the information that already exists comparing the languages and platforms from an academic or religious viewpoint, instead I seek to compare the languages and platform from an “in the trenches, personal experience” viewpoint.
- This is not intended to be comprehensive by any means. I don't know everything about .NET and I don't know everything about Java.
- While I have my personal preference, I am neither religious about the subject, nor do I intend to force the choosing of “sides”. What I do intend is to be as objective as possible and encourage an open-minded view where learning can be had from both sides.
There really isn't much difference in the basic syntax of the two languages. For the most part on a basic level, writing algorithms and designing classes in both languages looks pretty close to the same.
Classes
One of the first major differences I noticed when starting some work on a Java project, from primarily working in C#, was the ability to anonymously subclass a class on object creation and override it's methods. While I am generally against concrete inheritance, this Java language feature is very convenient for unit testing legacy code without requiring large refactors. Here is an example:
What is happening in this snippet is that I am anonymously inheriting from LegacyClass and providing an override for a method that created a concrete dependency. C# doesn't really have a way to specifically do this, which normally isn't a problem, but when unit testing legacy code it can be very useful.
On the other hand, C# allows partial classes, which is something I really wanted when working on some code generation work in Java. With C# you can define a class across multiple files. The real use of this is when you are generating code and you want to be able to have part of a class generated, but still have the other part of the class manually controlled and versioned.
I'll mention C#'s properties here, even though they can also be in the “Syntactic Sugar” section. C# properties essentially do what manually created getters and setters do in Java. I am not 100% convinced this is a good thing, but I will say it is useful. There is a strong argument that you should never write getters and setters, because they almost always violate data hiding. I am not in that camp yet, but I am leaning towards it more. Anyway, without going too far off topic, the property feature is very nice to have when you want it. When working in Java code I often expect to be able to just set something that I think should be a property and then I have to remember, “oh yeah, Java.”
Another important difference is that Java methods in classes are automatically virtual. In C# only methods with the virtual keyword are virtual. Although this isn't a big difference in design, I prefer not having something virtual unless I intend for it to be allowed to be overridden as opposed to having it default to virtual.
All in all, besides these differences, Java and C# classes are pretty similar. There is the whole inner class difference, but really you shouldn't be using inner classes. Yes, I know there are specific situations when they are useful, but for the most part in day to day programming they aren't and shouldn't be used.
Enumerations
I have to say, I love the Java enumeration. The ability to add some functionality to an enumeration is really very useful. Java made enumerations just like classes, (except they can't extend another class.) C# enumerations are more along the lines of C/C++ implementations in which they are just basically integers.
I use enumerations very often in my code. I find that restricting the set of options that can be passed into a method, makes the understanding that method more clear and reduces complexity in the system. The right place for the logic that goes along with an enumeration is in the enumeration. Java gets this one right.
My Big Beef: Function Pointers
I have long lamented not being able to remove a bunch of if/else conditions in Java with a map which maps a condition to function pointer. I will use the term “function pointer” here instead of delegate or closure. (Yes, I know all 3 are different.) Really what I am trying to achieve when I refer to function pointer, is finding a way to reference a method I want to call in Java without having to use the observer pattern.
C# handles this with delegates and an eventing framework. C# has expanded on this to the point where you don't even realize you are using function pointers. First, there were anonymous delegates, then there were Lambda expressions. This is where C# really shines. Lambda expressions allow a C# programmer to very succinctly express code as data and operate on it in that fashion. Here is an example:
There is just something magic about writing your first Lambda expression and having intellisense list your options inside code that looks like the compiler couldn't possibly know what the types are.
For you functional programming buffs, this isn't a big deal, but for us OOs it is amazing. I strongly believe Lambda expressions have the potential to completely change the way we think about programming algorithms and actually take them to a higher level of abstraction, much like the combination of collections and generics did.
I know that Java is supposed to get some form of closures in JDK7, but until it does, this is going to be a major weakness. Having worked through many programming problems in both languages, I can tell you that Lambda expressions can greatly simplify the expression and solution of a problem.
To Be Continued…
I don't want to write anything longer than I would want to read at one time. For that reason, I will cover more on language, including Generics, Exceptions, and Syntactic Sugar differences in C# vs. Java tomorrow.