Java and C# - A Programmer's Comparison

by Thomas Paul

Introduction


There are articles all over the internet comparing C# and Java so why am I writing one? I started programming in Java in 1996 after several years of developing applications in C++. Since April of 2002, I have been writing programs in C#. That means over the last 10 years I have developed real life production applications in C++, Java, and C#. I also don't have any ax to grind. I think I can be fair in an evaluation of C#, something that seems to be missing in many of the evaluations I have read.

The question of why C# was invented has more to do with the politics between Sun and Microsoft than anything else. Once Microsoft was excluded from the Java world, the development of C# was virtually assured. Microsoft needed a new language to go with their .Net environment and C++ and VB were simply too complicated or too limited for this new environment.

So is C#, Microsoft's brand of Java? To put it simply, yes. C# is a lot like Java and a Java developer will find the transition between the two languages to be very simple. You will find that many things in the language are identical, some other things are very similar, while a few others are very different. Rather than do a complete comparison of the two languages, I would like to discuss those things that Java programmers (in my opinion) will either wish Java had or will hate.

Things I Hate in C#

Operator Overloading


This was in C++ and I hated it in that language. For those who are unfamiliar with the idea behind operator overloading, I will give you an example out of Java. The String class has the plus sign overloaded so that you can concatenate two Strings. This is a convenience so that we can code s1 = s2 + s3 instead of s1 = s2.concat(s3). However, when operator overloading is unlimited, we end up with odd constructs. In C#, you can overload any operator including ==, !=, < , and >. So instead of using an equals method to compare two objects, you can overload the equals operator to compare any two objects. This might sound nice, but can easily cause confusion. Is obj1 == obj2 a reference compare or an object contents compare? There's no way to know unless you look at the API. Of course, we have the same problem with the equals method in Java since it may or may not be overridden but at least we always know that == is a reference compare. In C#, if == is overloaded, there is no way to do a reference compare! You might think that this isn't too bad but what about other operators? What does it mean if I do employee1 = employee2 + employee3? Although there may be times when it is useful (date1 = date2 - date3) , it tends to create more confusion than it is worth.

One capability with operator overloading that is very nice is the ability to create castings between classes. C# allows you to create explicit or implicit casts between classes that would not normally be permitted. For example, let's say that we have an Employee class that is the parent of ExemptEmployee and NonExemptEmployee. In Java there is no way to cast a NonExemptEmployee to be an ExemptEmployee. C# allows you to set up a method to do just that. The method will take in a NonExemptEmployee and return an ExemptEmployee. The method gets executed automatically when casting is needed (implicit) or when a cast is made (explicit). This can be very useful if you have a method that takes in ExemptEmployee objects but all you have is a NonExemptEmployee object.

Properties and Indexers


We all know by now that properties should be kept private and then accessed through public get and set methods. The makers of C# agree with this concept but rather than use Java-like public get and set methods, they designed a way to make it look like you are accessing public properties even though you are really running get and set methods. In this way you can code office1.DeptNum = 101 and actually be running a set method. The code looks like this:
public int DeptNum 
{
	get 
	{
		return deptNum;
	}
	set
	{
		deptNum  = value;
	}
}

I find this to be confusing and the saving over coding office1.setDepartment(101) is trivial.

Indexers are also confusing. The idea with an indexer is that you can make an object appear to be an array. For example, let's assume that you have a department class that you want to use to hold multiple office objects. Rather than use a method like dept1.addOffice(office1), you can use dept1[0] = office1. To a Java programmer, dept1 looks like an array of Office objects. In fact, dept1 is a Department class that can hold all sorts of information about departments including an array of offices in that department. The big problem is that it isn't clear exactly what kind of object should be added using the indexer. With an addOffice method you know you are adding an Office object. But using dept1[0] isn't clear at all.

Properties and indexers drive me crazy because they seem to be deliberately designed to fool programmers into believing something about a class that isn't true.

Pass by Reference


Just as in Java, C# uses pass by value. But C# also allow the programmer to pass by reference. Although parameters passed by reference must be clearly identified, the whole concept of pass by reference seems very anti-OO to me because you are accepting side effects as being desirable. Methods should return values, not replace values passed to them. This isn't a terrible thing, but I could have easily lived without it.

Catching Exceptions


C# does not require you to catch exceptions. I don't understand why this is the case because forcing exceptions to be caught makes for cleaner, more reliable code. In Java, if you fail to catch an exception, you get a nice compile error that let's you know what exceptions a method can throw. This makes it easy to write reliable code without having to check the API every time you make a method call. C# does not give any warnings when you fail to code a catch around a method call. This forces you to check the API to figure out what exceptions might be thrown. A definite pain in the neck. The end result is that try...catch isn't used nearly as often as it should be in C#.

Polymorphism


C# uses the C++ model for polymorphism which means you must take positive action to make a method eligible to take part in polymorphism. What does this mean exactly? In Java, you can override a method in your parent class and as long as the parent method isn't final there isn't a problem. You get runtime method binding which is very powerful. C# prefers to use compile-time binding unless you specifically tell it otherwise. C# adds three keywords to make this all work; virtual, override, and new. Since programmers tend to not code their classes with the next programmer's concern in mind, it is very unlikely that the original programmer will write the necessary code to insure that programmers extending their class will be able to override their methods. Java wins hands down in this area.

Things I Love in C#

foreach


The foreach statement is one of the most convenient ways to iterate through a collection or an array. It allows you to process an entire collection and cast the objects to the correct type in one handy little statement. Here's an example:
public void AMethod(ArrayList list) 
{
	foreach (Employee emp in list)
	{
		Console.WriteLine(emp.Name);
	}
}

To do the same thing in Java would require creating an iterator and running a while loop. The only problem with this is that if list contains something other than an Employee object, the foreach will throw a ClassCastException.

Enumerators


This is something that really belongs in Java. It helps create more reliable code by insuring type safety at compile time. For example, if you have a field that should only contain the days of the week, to insure type safety at compile time, you would have to create a special class to insure that only the days of the week can end up in the field. This can only be tested at runtime. Using an Enumerator, you can test what is being moved to the field at compile time. How do we do this?

First we create an enumerator which contains the days of the week:
enum DayOfTheWeek
{
	Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
}


Now we define our field as being of type DayOfTheWeek. By doing so, our variable can only hold one of the seven DayOfTheWeek enumerations:
DayOfTheWeek day; 
day = DayOfTheWeek.Sunday;

Automatic Boxing of Primitives


You have an int and you want to stick it into a collection. Or you have a float and you want to convert it into a string. In C# this is a breeze. Whenever you use a primitive in a place that requires an object, C# automatically turns the primitive into an object. This is called "boxing". basically it means that you can treat all your primitives as if they were objects without paying the overhead of having them always be objects. So you can do something like this:
int i = 50;
arrayList.Add(i);
string s = i.ToString( );

Delegates


One of the nice things about C++ is the ability to use function pointers. Delegates give you a very similar functionality. In many ways it is similar to the event model used in Java but it has the added advantage of not tying you to a particular method name. One of the problems with Java's event model is that if you use one class to receive event notifications from different objects (let's say one class is handling the action event for three Buttons) then all the notifications will go to the same method. The method has to figure out which Button caused the method to be triggered. The delegate model allows you to have different methods for each Button object if you wish. Instead of passing just an object to be notified, the delegate model allows you to pass a method to be called when the event is triggered.

OKButton.Click += new System.EventHandler(buttonHandler.OKButton_Click);
CancelButton.Click += new System.EventHandler(buttonHandler.CancelButton_Click);

Notice that setting up a delegate involves using operator overloading. In this case, when the OKButtum is clicked, the OKButton_Click method of the buttonHandler object will be invoked. When the CancelButton is clicked, the CancelButton_Click method will be invoked. The actual method has to have a certain signature that is determined by the delegate model that is used. For button clicks, the method signature looks like this:

private void OKButton_Click(object sender, System.EventArgs e) { }

Although the delegate model is used for events, it can be used for any situation where a callback is useful.

The C# switch statement


There are two nice improvements in the switch. First, you can use a string in your case. Second, there is no way to accidentally fall through from one case to another. If you want to fall through you have to specifically tell the compiler.

Multi-dimensional Arrays


C# provides direct support for multi-dimensional arrays. It also supports the jagged arrays found in Java. You can code this kind of construct:

string[,] cityState = new string[25,2];

The as keyword


C# has the "is" keyword which is basically the same as instanceof. You can code something like: if (a is Animal). But C# also has the "as" keyword which is used for casting.

Look at this piece of Java code (assume that Animal is the parent class of Dog):
Dog d;
Animal a = new Animal();
d = (Dog)a;  // ClassCastException

Although this code compiles, it causes a runtime ClassCastException. We would need to use an instanceof before the cast to insure that the cast will work. That is what the "as" does in C#. You can do this:
Dog d;
Animal a = new Animal();
d = a as Dog;

If this is not a valid cast (a is not a Dog or a child of Dog), d will contain null and no ClassCastException occurs. Of course, C# allows you to use a regular cast as well.

Final words


So which is the better language? They are both great languages and I enjoy working in both of them. Both languages have all the features that you expect in a modern object oriented language. Knowledge of one of these is easily transferred to the other. Thebest part is that C# has opened the Microsoft world to Java developers. By removing the reliance on C++ and Visual Basic, .Net has created an opportunity for Java programmers to take their skills into a job market that was previously closed to them.

By the way, some of the things I pointed out as things I like about C# are planned to be added to Java at some point. You can take a look at the "From Mantis to Tiger" site for a look at some of the proposed enhancements in J2SE 1.5.