Jump to content

Comparison of C Sharp and Java

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Int19h (talk | contribs) at 07:14, 7 November 2006 (reword and clarify why virtual method calls are slower). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

#

This is a comparison of the C# programming language with the Java programming language. As two modern garbage-collected runtime-compiled languages derived from C and C++, Java and C# are very similar. This page documents the strong general similarities of the languages and then points out those instances where the languages diverge. Both languages were designed carefully, and if one language has a feature another lacks it is the result of a conscientious design decision. Thus, the reader is advised to avoid the temptation to 'keep score,' and instead think about why the designers made each decision.

Language

Object handling

Both languages are object oriented from the ground up, with a syntax similar to C++. (C++ in turn is derived from C.) Neither language is a superset of C or C++, however. Both use garbage collection as a means of reclaiming memory resources, rather than formal deallocation of memory. And both include thread synchronization mechanisms as part of their language syntax.

Both Java and C# have strong and weak object references. Java allows registering a listener that will be notified when a reference is garbage collected, which allows for the good performance of the WeakHashMap that C# lacks. C# only supports this by using a finalizer (which is also available in Java). C# on the other hand allows the programmer to suppress the finalizer of a specific object (e.g., an SQL connection or a file stream that always needs to be properly closed). This can be very useful since finalizers are expensive in generational garbage collection (applied by both Java and .NET), and are often used only as a fail-safe for when the programmer doesn't close the object. An object with a finalizer will normally be promoted to an extra generation and kept alive longer before it is collected.

C# allows restricted use of pointers, which are considered unsafe by some language designers. C# addresses that concern by requiring that code blocks or methods that use the feature be marked with the unsafe keyword, so that all clients of such code can be aware that the code may be less secure than otherwise. The compiler requires the /unsafe switch to allow compilation of a program that uses such code. Generally, unsafe code is only used to allow beter interoperability with unmanaged API's or system calls (which is inherently "unsafe"), or sometimes as a small performance enhancement.

Data types

Both languages support the idea of primitive types (known as value types in C#), and both allow boxing and unboxing to translate primitive data to and from object form. C# has more primitive types than Java, with unsigned as well as signed integer types being supported, and a special decimal type for precise floating-point calculations. Java forgoes most unsigned types in favour of simplicity. In particular, Java lacks a primitive type for an unsigned byte. Strings are treated as (immutable) objects, but support for string literals provides a specialised means of constructing them. C# also allows verbatim strings for quotation without escape sequences, that also allow newlines.

C# allows the programmer to create user-defined value types, using the struct keyword. From the programmer's perspective, they are similar to classes, but with a number of limitations: they cannot have a default constructor with no argument (but can have non-default constructors with one or more arguments), and cannot extend other classes or be extended (but can implement interfaces). Unlike class instances, instances of value types are not allocated on the heap, but rather on the stack, or as part of the object instance in which they are declared.

Enumerations in C# are derived from a primitive integer type. Any value of the underlying primitive type is a valid value of the enumeration type, though an explicit cast may be needed to assign it. This allows to combine enumeration values together using the bitwise OR operator if they are bit flags. Enumeration values in Java, on the other hand, are objects. The only valid values in a Java enumeration are the ones listed in the enumeration. A special enumeration set object is needed to combine enumeration values together. Java enumerations allow differing method implementations for each value in the enumeration. Both C# and Java enumerations can be converted to strings, but only Java enumerations allow to customize such conversion.

Array and collection types are also given significance in the syntax of both languages, thanks to an iterator-based foreach statement loop. In both languages an array corresponds to an object of the Array class, although in Java this class does not implement any of the collection interfaces. C# has true multi-dimensional arrays, as well as the arrays-of-arrays that are available in Java (and which in C# are commonly called jagged arrays). Multi-dimensional arrays can in some cases increase performance because of increased locality (as there is a single pointer dereference, instead of one for every dimension of the array as is the case for jagged arrays). Another advantage is that the entire multi-dimensional array can be allocated with a single application of operator new, while jagged arrays require explicit loops and allocations for every dimension.

Java 1.5's generics use type erasure. Information about the generic types is ignored at runtime, and only obtainable via reflection on the static class objects. In .NET 2.0, information on generic types is fully preserved at runtime. Java's approach requires additional type checks, does not guarantee that generic contract will be followed, and lacks reflection on the generic types. Java does not allow to specialize generic classes with primitive types, while C# allows generics for both reference types and value types, including primitive types. Java instead allows the use of boxed types as type parameters (e.g., List<Integer> instead of List<int>), but this comes at a cost since all such values need to be heap-allocated. In both Java and C#, generic specializations that use different reference types use equivalent underlying code[1], but for C# the CLR dynamically generates optimized code for specializations on value types. In .NET 2.0, type safety for generics is fully checked at compile time and enforced at load time by the CLR. In Java, it is only partially checked at compile time and needs to be enforced using cast operations at runtime, as the Java VM is not aware of generic types.

Notation and special features

Java has a static import syntax that allows using the short name of some or all of the static methods/fields in a class. C# has a static class syntax, which restricts a class to only contain static methods, but does not provide any facility to access those methods without explicitly referencing the class on each access.

Special feature keywords

keyword feature, example usage
get, set C# implements properties as part of the language syntax, as an alternative for the accessor methods used in Java.
out, ref C# has support for output parameters, aiding in the return of multiple values.
switch In C#, the switch statement also operates on strings.
strictfp Java uses strictfp to guarantee the result of floating point operations remain the same across platforms.
checked, unchecked In C#, checked statement blocks or expressions can enable run-time checking for arithmetic overflow.
using C#'s using forces the object created to be disposed or closed after the code block has run.
// Create a small file "test.txt", write a string, and close it (even if an exception occurs)

using (StreamWriter file = new StreamWriter("test.txt"))
{
   file.Write("test");
}
goto C# supports the goto keyword. This can occasionally be useful, but the use of a more structured method of control flow is usually recommended. A common use of the goto keyword in C# is to transfer control to a different case label within a switch statement. Both C# and Java allow qualified breaks and continues, which make up for many of the uses of goto.
switch(color)
{
   case Color.Blue: Console.WriteLine("Color is blue"); break;
   case Color.DarkBlue: Console.WriteLine("Color is dark"); goto case Color.Blue;
   // ...
}

Event handling

Java requires the programmer to implement the observer pattern manually, though it provides some syntactic sugar in form of anonymous inner classes, which allow to define the body of the class and create an instance of it in a single point in the code. This is typically used to create observers.

C# provides extensive support for event-driven programming at language level, including delegate types. These are type-safe references to methods and can be combined to allow multicasting. To support them there is a special syntax to define events in classes and operators to register, unregister or combine event handlers. Delegates support covariance and contravariance, and can be created as anonymous methods with full-featured closure semantics.

Closures have also been proposed as a new feature for Java SE 7. [2] Like delegates in C#, such closures would have full access to all local variables in scope, not just read-only access to those marked final (as with anonymous inner classes).

Operator overloading

C# includes a large number of notational conveniences over Java, many of which, such as operator overloading and user-defined casts, are already familiar to the large community of C++ programmers. It also has "Explicit Member Implementation" which allows a class to specifically implement methods of an interface, separate to its own class methods, or to provide different implementations for two methods with the same name and signature inherited from two base interfaces.

Java does not include operator overloading, because abuse of operator overloading can lead to code that is harder to understand and debug. C# allows operator overloading (subject to certain restrictions to ensure logical coherence), which, when used carefully, can make code terser and more readable. Java's lack of overloading makes it somewhat unsuited for certain mathematical programs.

Methods

Methods in C# are non-virtual by default, and have to be declared virtual explicitly if desired. In Java, methods are virtual by default, and there is no way to make them non-virtual. Virtualness guarantees that the most recent override for the method will be called, but incurs a certain runtime cost on invocation as these invocations cannot be normally inlined, and require an indirect call via the virtual method table. Some JVM implementations, including the Sun reference implementation, implement inlining of the most commonly called virtual methods to reduce the runtime overhead from virtual method calls.

C# furthermore requires explicit declaration of intent when overriding virtual methods in a derived class. If method should be overriden, the override modifier should be specified. If overriding is not desired, and the class designer merely wishes to introduce a new virtual method with the same name and signature, shadowing the old one, the new keyword should be specified. It is a compile error for neither modifier to be present. In Java, any method always overrides the method in the base class with the same signature and name, if such is present. This behavior can be potentially dangerous if the base class is designed by a different person, and a new version of it introduces method with the same name and signature as some method already present in the derived class; in this case, the method in the derived class will implicitly override the method in the base class, even though that was not the intent of the designers of either class. To partially accommodate for these problems, Java 5.0 introduced a @Override annotation, but to preserve backwards compatibility it could not be made compulsory.

Conditional compilation

Unlike Java, C# supports conditional compilation using preprocessor directives. It also provides a Conditional attribute to define methods that are only called when a given compilation constant is defined. This way, assertions can be provided as a framework feature with the method Debug.Assert(), which is only evaluated when the DEBUG constant is defined. Since version 1.4, Java provides a language feature for assertions that can be enabled and disabled at runtime.

Namespaces and source files

C#'s namespaces are more similar to those in C++. Unlike Java, the namespace is not in any way tied to location of the source file. While it's not strictly necessary for a Java source file location to mirror its package directory structure, it is the default behavior.

Java requires that a source file name must match the only public class inside it, while C# allows multiple public classes in the same file, and puts no restrictions on the file name.

As of version 2 C#, by using the keyword partial in the class definition, allows to split a class into several files.

Exceptions

Java support for checked exceptions enforces error trapping and handling. C# does not include checked exceptions. Some would argue that checked exceptions are very helpful for good programming practice. Others, including Anders Hejlsberg, chief C# language architect, argue that they were to some extent an experiment in Java and that they haven't been shown to be worthwhile except for in small example programs.[3][4] One criticism of checked exceptions is that a new implementation of a method may cause unanticipated checked exceptions to be thrown, which is a contract-breaking change. To allow for unanticipated implementations, some programmers declare "throws Exception", which defeats the purpose of checked exceptions. However, any new types of exceptions could be caught and re-thrown in an a wrapper exception. For example, if an object is changed to start accessing a database instead of a filesystem, a SQLException could be caught and re-thrown as an IOException, since the caller does not need to know the inner workings of the object.

Lower level code

The Java Native Interface (JNI) feature allows Java programs to call non-Java code. However, JNI does require the code to be called to follow several conventions and impose restrictions on types and names used. This means that an extra adaption layer between legacy code and Java is often needed. This adaption code must be coded in a non-Java language, often C or C++.

In addition, third party libraries provide for Java-COM bridging, e.g. JACOB (free), and J-Integra for COM (proprietary).

.NET Platform Invoke (P/Invoke) offers the same capability by allowing calls from C# to what Microsoft refers to as unmanaged code. Through metadata attributes the programmer can control exactly how the parameters and results are marshalled, thus avoiding the need for extra adaption code. P/Invoke allows almost complete access to procedural APIs (such as Win32 or POSIX), but no direct access to legacy C++ class libraries.

In addition, .NET Framework also provides a .NET-COM bridge, allowing access to COM components as if they were native .NET objects.

C# also allows the programmer to disable the normal type-checking and other safety features of the CLR, which then enables the use of pointer variables. When this feature is used, the programmer must mark the code using the unsafe keyword. JNI, P/Invoke, and "unsafe" code are equally risky features, exposing possible security holes and application instability. An advantage of unsafe, managed code over P/Invoke or JNI is that it allows the programmer to continue to work in the familiar C# environment to accomplish some tasks that otherwise would require calling out to unmanaged code. A program or assembly using unsafe code must be compiled with a special switch and will be marked as such. This enables runtime environments to take special precautions before executing potentially harmful code.

Implementations

JVM and CLR

Java is ubiquitous across many disparate operating systems and environments. Numerous JVM implementations exist, some under open source licensing.

Java Webstart and Java applets provide convenient, lightweight and secure means of distributing an application to the desktop, while the efficiency of its bytecode representation, coupled with aggressive Java-specific compression technologies such as pack200, makes Java a very bandwidth-friendly means of distributing applications over a network.

C# is also a cross-platform standard. The primary platform is Windows, but implementations do exist for other platforms as well, most notably the Mono Project.

The ClickOnce technology offers comparable functionality to Java Webstart, although it is only available for Windows clients. Internet Explorer on Windows also displays .NET Windows Forms controls. This does allow for applet-like functionality, but is limited to a specific browser.

Standardization

C# is defined by ECMA and ISO standards, whereas Java is largely controlled through a Java Community Process (JCP) which allows interested proprietary parties or open source parties to be involved in the definition of future versions and features of the Java™ technology specifications. The C# standard only defines the language and foundation classes (known as the Base Class Library, or BCL), but do not include APIs for accessing databases, or building GUI and Web applications, such as Windows Forms, ASP.NET and ADO.NET. All three are thus proprietary libraries from Microsoft.

Usage

Community

Java embraces a more open culture, with many competing vendors for functionality. While this completely solves the problem of vendor lock-in, it adds additional complexity to the language. One must not just be familiar with Java, but also all of the various competing frameworks and different implementation gotchas.

Notwithstanding the existence of Mono, C# has vendor and platform lock-in. This significantly simplifies development, as there is one solution, like it or not.

Java follows a more pure approach to development. Java frameworks tend to have a large number of classes that interact with each other, with many layers of abstraction. This allows for a significant amount of power in the frameworks, but learning a new framework can be difficult, and even the "hello world" of some situations can be quite complex.

C# follows a more pragmatic approach. Simple helper classes are often provided in addition to the nested layers of abstraction; in some cases the abstraction layers are not provided at all.

Popularity and evolution

Java is older than C# and has built up a large and highly active user base, becoming the lingua franca in many modern branches of computer science, particularly areas which involve networking. Java dominates programming courses at high school and college level in the United States, and there are currently many more Java than C# books. Java's maturity and popularity have ensured more third party Java API and libraries (many of them open source) than C#.

By contrast, C# is a relatively new language. Microsoft has studied existing languages such as Java and Delphi, building on their successes, and changed some aspects of the language to better suit certain types of applications. Over time Java's headstart may become less relevant.

An occasionally voiced criticism of the Java language is that it evolves slowly, lacking some features which make fashionable programming patterns and methodologies easier.[citation needed] An occasionally voiced criticism of the C# language is that its designers are perhaps too quick to pander to current trends in programming - lacking focus and simplicity.[citation needed] Certainly Java's designers seem to have taken a more conservative stand on adding major new features to their language syntax than other current languages - perhaps not wanting to tie the language too tightly with trends which may in the medium/long term be dead ends. With the Java 5.0 release, this trend may have been broken, as it introduced several new major language features: foreach statement, autoboxing, methods with variable number of parameters (variadic functions), enumerated types, generic types, and annotations - though all of those but generic types were already present in C# by that time, some under different names.[5]

C# has evolved rapidly to attempt to streamline development for problem-specific features. C# 3.0 adds a SQL-like language integrated queries suited for querying data from collections, databases or XML documents. It however builds upon general-purpose language features; lambda expressions and extension methods features, that also allow such queries to be expressed and optimized for user types. Problem-specific language additions to Java have been considered and, for now at least, rejected. This approach, along with a number of other new languages and technologies which address themselves specifically at current programming trends, has sparked a renewed debate within the Java camp about the future direction of the Java language and whether its 'conservative evolution' is right.

Marketplace

Since C#'s inception the two languages have been compared and contrasted. It is undeniable that C# and the CLR (Common Language Runtime) managed code environment in which most C# applications run owe a lot to Java and the JRE (Java Runtime Environment). However C# also accommodates constructs more commonly found in languages such as C++, Delphi (designing which was Anders Hejlsberg's principal job when he was at Borland), and, in recent C# versions, borrowing from dynamic scripting languages such as Ruby.

It can be argued that Microsoft developed C# in some part as a result of recognising that the managed code environment which Java champions has many virtues in an increasingly networked world, particularly as the internet moves out onto devices other than personal computers, and security becomes ever more important. Before creating C#, Microsoft modified the Java language (creating "J++") in order to add features which run only on Windows operating system, thus violating Sun Microsystems' license agreement. Microsoft was in the second phase of their business strategy known as embrace, extend and extinguish, and eventually J++ was blocked by a lawsuit brought by Sun Microsystems, the owner of Java. Unable to produce a flavor of Java with the features it wanted, Microsoft created an alternative which more appropriately suited their own needs and vision of the future.

Despite this fractious start, as time has passed it has become apparent that the two languages rarely compete one-on-one in the marketplace. Java dominates the mobile sector, and has a large following within the web based applications market. C# is well recognised in the Windows desktop market, and is being pushed by Microsoft as the language for Windows applications. C# is also a player in the web application market, thanks to ASP.NET.

Desktop applications

Java has sometimes been accused of promising much and delivering little when it comes to desktop applications. It is true that although Java's AWT (Abstract Windowing Toolkit) and Swing libraries are not shy of features, Java has struggled to establish a foothold in the desktop market. Its rigid adherence to the notion of write once, run anywhere makes it difficult to use to the maximum the unique features and modes of working within each individual desktop environment. As a result, desktop applications written in Java are often accused of looking "alien" on any platform they are run on.

Sun Microsystems has also been slow, in the eyes of some, to promote Java to developers and end users alike in a way which makes it an appealing choice for desktop software. Even technologies such as Java Web Start, which have few parallels within rival languages and platforms, have barely been promoted.

The release of Java version 6.0, sometime in 2006, sees a renewed focus on the desktop market — with an extensive set of new and interesting tools for better and closer integration with the desktop.

Server applications

This is probably the arena in which the two languages are closest to being considered rivals. Java, through its J2EE (aka JavaEE, Java(2) Enterprise Edition) platform, and C# through ASP.NET, compete to create web based dynamic content and applications.

Both languages are well used and supported in this market, with a bevy of tools and supporting products available for JavaEE and .NET.

Mobile applications

Java's J2ME (aka JavaME, Java(2) Micro Edition) has a very large base within the mobile phone and PDA markets, with only the cheapest devices now devoid of a KVM (a cut down Java Virtual Machine for use on devices with limited processing power). Java software, including many games, is commonplace.

While almost every mobile phone includes a JVM, these features are not heavily used by most users (particularly in the United States). Java applications on most phones typically consist of menuing systems, small games, or systems to download ringtones etc. Full featured cell phone applications are rare.

In the Smartphone and PDA market, Windows Mobile is gaining ground quickly, and Windows Mobile is becoming the preferred platform for writing heavy business applications. Windows Mobile is based on the Windows CE platform and uses the .NET Compact Framework (.NETCF) instead of the full version of the .NET Framework. The .NETCF is a powerful subset of the full .NET Framework that has some specific functionality for mobile devices.

See also

References