If we could have the best of both worlds between C# and Java, what would that look like?

The perfect programming language doesn’t exist. I hope we can agree on that, if nothing else. New languages are often developed in response to the shortcomings of another, and each is inevitably stronger in some ways and weaker in others.

C# and Java both stemmed from C/C++ languages, and they have a lot in common beyond both being Object-oriented. In addition to some structural similarities between Java’s JVM and C#’s .NET CLR, each advanced on its own path with their respective development teams focused on different visions of what the language should be.

We don’t want to get lost in the argument of which language is better than the other, we just want to outline some of the features that developers in C# are using that we don’t have available to us in Java.

Let’s get started.


LINQ (Language-Integrated Query) was introduced to C# in 2007 to help developers query data from various sources. With it, we can write queries without needing to take into consideration the appropriate syntax for the specific database being called on. A component of LINQ, the LINQ provider, converts the query to a format that’s readable by the underlying source. For example, if we need to query data from a SQL database, the LINQ to SQL provider will convert the LINQ query into T-SQL so that the database can understand it.

To perform a query operation in LINQ, first the database is obtained, then the query is created and finally it’s executed. In LINQ to Object queries, this can be as simple as a single line of code, rather than writing complicated iterations of nested for each loops.

For example, let’s look at this code for filtering 2-digit numbers from a list in C#.

First, without using LINQ:

And then using LINQ in query syntax:

And method syntax:

Both syntaxes here are correct, the only real difference is that the query syntax looks more like SQL and the method syntax uses lambda expressions (and thus, looks like something we might write in Java).

Bottom Line: Many of the features that LINQ relies on, such as lambdas, are useful in their own right and already have equivalents that were implemented in Java. So, while we can use streams and lambdas for querying data, LINQ streamlines the process and removes much of the verbosity that still exists in Java.

2. Struct

Structs in C# are used similarly to classes. In fact, a struct can even be considered to be a “lightweight class” itself as it can contain constructors, constants, methods and more. The biggest difference between a struct and a class is that structs are value-types while classes are reference-types.

The most significant benefit of writing a struct over creating a class is that it is easier to ensure value semantics when constructing a value-type than it is when constructing a reference-type. As stated in Microsoft’s documentation, “a variable of a struct type directly contains the data of the struct, whereas a variable of a class type contains a reference to the data.” So, one of the benefits of using a struct over a class is that the only way to alter its value from other parts of the code is by explicitly passing it as a reference.

Developers at Microsoft recommend using a struct in place of a class only for types which are smaller than 16 bytes, are immutable, are short-lived and are not frequently boxed. Under these circumstances, using a struct may also be slightly more efficient than using a class because it will more likely be stored in the stack rather than in the heap.


Bottom Line: In many situations, writing a struct can appear to save time on memory allocation and deallocation and, thus, be more appealing. The truth is, though, that value-types are stored wherever they are owned. Regardless of the apparent benefits or drawbacks of using structs, we don’t have to worry about any of this when it comes to Java.

3. Async/Await

By calling async on a code part, or more specifically on a method, that method will be executed on a separate thread so as to not block the current thread. When the code reaches the await command, it will continue running. If at that point, the async code hasn’t finished, then the execution will return to its calling method.

This can help improve the overall responsiveness of your application and help to reduce performance bottlenecks. Using asynchronous programming is very important for applications when trying to access the web and for all UI-related activities. Compared to previous techniques of implementing asynchronous programming, the use of async/await preserves the logical structure of your code and the compiler does the heavy lifting that used to be required of the developer.


The output:

Bottom line: CompletableFutures undoubtedly brought us closer to having equivalent capabilities in asynchronous programming in C# and Java. Still, the complicated nature of using it makes it no match for the ease with which the async/await keywords can be implemented.

4. Lazy<T> Class

Whether working in C# or in Java, many of us have implemented lazy initialization (or instantiation) so that an object is not created until the first time that it will be used. One of the more common instances that lazy initialization is used for is when an application loads many objects upon launching but only requires a few of them initially. In this case, we want to instruct unnecessary objects to initialize only when needed to improve the performance of our application.

Bottom Line: Implementing lazy initialization recently became much easier in Java (as did many other things) when lambda expressions were introduced in Java 8. Still, in C# we can use the Lazy<T> wrapper class which provides the semantics of lazy initialization for any class library or user-specified type.

5. Some Keyword Equivalencies

Useful features in languages don’t have to be as big of an undertaking as implementing something like LINQ in C# or modules in Java. Here are some keywords that help C# developers that we don’t have in Java:

a. as

The as keyword in C# attempts to safe-cast an object to a type, and if it can’t it returns null. Java’s instanceof is almost comparable, but it is a boolean that returns true if the types match and false if they don’t.

b. Yield

Yield and return yield are used in C# to perform custom and stateful iterations without an explicit extra class and without the need to create a temporary collection. Our best options for implementing iterations in Java seem to be accessing an external library or using lambdas which were introduced in Java 8.

c. var

Var is an implicit type that is determined by the compiler and is functionally equivalent to writing an explicit type (i.e. int, string, etc.). Aside from saving a few extra keystrokes, var allows for anonymous types which are most typically used in LINQ queries. We’re expecting to see a “var” identifier implemented in the highly anticipated Java SE 9 which will “extend type inference to declarations of local variables with initializers.”

d. Checked

In C#, we use the checked keyword to explicitly enable overflow checking for integral-type expressions. If the resulting value of some expression is outside the range of the destination type, we can use checked to force the runtime to throw an OverflowException. This is helpful because while constant expressions have overflow checking at compile time by default, non-constant expressions do not.

Tooling Ecosystems

There are many more differences between Java and C#, of course, some of which are rooted in the differences in the Java and .NET frameworks. With these differences, come differences in compatibilities of helpful tools like OverOps that provide production monitoring and error tracking.

OverOps shows developers the complete source code and variable state across the entire call stack for every error in production. It doesn’t currently have any equivalent for the .NET framework, but that’s going to change in the next few months. For more information and to join the waiting list for our .NET Beta click here, or if you’re a Java developer check out www.overops.com to request a demo.

Final Thoughts

At the end of the day, most of the features we mentioned here give C# developers an advantage in terms of the length and clarity of their code rather than in enabling them to write code that can’t be written in Java. It’s also true that much of what made Java a more verbose language was addressed, at least partially, by the inclusion of lambda expressions in the most recent version update. Still, a lot of these features that we find in C# and not in Java simplify the syntax of common use cases beyond what lambdas offer.

Again, we don’t want to get involved in the never-ending argument over which language is better, we’re just here to point out some of the differences between the two. Did we miss any features that you would love to have in Java? Let us know in the comments!


Looking for more posts like this?

Join our force of more than 30,000 Java Jedi masters!

Watch a live demo
Tali studied theoretical mathematics at Northeastern University and loves to explore the intersection of numbers and the human condition. In her free time, she enjoys drawing and spending time with animals.
  • Richard Markle

    Aren’t LINQ and JPA pretty similar in concept?

    • Jorge Garay

      Spring Jpa currently gives some really nice features currently and Java 9 is almost here, then again as programmers we must keep in mind that every languages is a tool and you don’t want to use the wrong tool for a job, it would be like hammering a screw, you may get it in but you would have it sooner and better with a screwdriver.

      • c_world_poster

        Yup. With Spring Data JPA, i almost NEVER right a query any more. With Java 8, i can do anything i would need to in LINQ… and be readable. As for XML … who still does that. If i need to, i use Groovy XML Slurper.

    • edino

      Linq works with almost anything, SQL, XML, in memory collections …, and it’s based on language features such as lambda and expression trees.

  • Andre Dias

    Really good and I agree that there is no perfect language.
    Now, we’d kill to know what Java has that C# would kill to have it!
    It’s fair, isn’t it?

    • Tali Soroker

      Spoilers! We’re working on it now, stay tuned (:

    • c_world_poster

      Spring, Spring Boot Hibernate, most of what is in Apache.org, Netflix Libs and tools, real choice in IDEs, more than one application server … i could go on. Language differences are of little importance in 2017.

  • Gonzalo Ortiz Jaureguizar

    Structs will be implemented on Java as Value Types, which are being develop under the umbrella of the Project Valhalla at OpenJDK http://openjdk.java.net/projects/valhalla/.
    Sadly, they are not going to be ready for Java 9, so we will need to wait, at least, until Java 10

    • gacl

      Valhalla Value Types look way more sophisticated than C# structs. They better be given that they are coming ~20 years later. C# structs allow mutability which was a mistake. There are lots of gotchas where mutable C# structs can cause hard to spot problems. Also, the cited recommended limitations of 16 bytes and short lived objects are very limiting. Notice that even the .NET 4.0 library tuples don’t use C# structs which is a classic value type use case.

      • http://bartoszsypytkowski.com/ Bartosz Sypytkowski

        1. More than 90% of C# structs, you’ll going to deal with are immutable (eg. DateTime or TimeSpan) and it’s a common knowledge inside community to stick to that. You can also enforce field immutability (readonly keyword).

        2. There’s no limit for struct size, 16B is only guideline as structs are passed by value (so the content of the struct is copied)… which also can be mitigated by using ref keyword to avoid copying.

        3. Tuples are usually used internally (it’s an anti-pattern to expose tuples in public API). Moreover current versions of .NET already introduced value tuples, as well as value tasks – a common API for asynchronous Future-like types, designed to introduce no heap allocations for hot paths, where asynchronous value may be already completed.

        • gacl

          C# 7 tuples, pattern matching, and record types are all extremely useful features that should be on this list, and all Java programmers should want. Structs are simply less useful of any of those. And, of course, all three of those killer features have been in Scala since v1.0 for JVM programmers that want that: native tuples, pattern matching, record types.

  • gacl

    #1 just shows LINQ as simple functional collections with filter or where. Java 8 has this with the same level of conciseness.

    public static List filterTwoDigitNumbers(List l) {
    return l.stream().filter(i -> i > 9 && i < 100).collect(Collectors.toList());

    • Tali Soroker

      In terms of querying in-memory data, you’re absolutely right. With the introduction of streams in Java 8, LINQ wouldn’t necessarily add much to our abilities to, for example, filter data from objects in the heap. I think that one of the main benefits that we get from LINQ is the ability to query data from other data sources such as SQL databases or XML documents without needing to change our syntax.

      • gacl

        Yes. The OP strictly showcases in-memory collections and we agree that Java 8 collections have that. For SQL databases, LINQ offers nice features like compilation time syntax checking that you don’t usually get with SQL, but most devs will still prefer plain SQL. Additionally, last I checked LINQ only fully integrates with Microsoft SQL Server and not with popular options like Postgresql. And there are tons of similarly competent library options for concise XML querying/processing.

        • Isaac

          There are many LINQ providers on .NET, including a Postgresql one.

          • gacl

            AFAIK, it is a completely third party unofficial solution not supported by either Postgres or Microsoft, right?

          • Isaac

            Yep. Just like lots and lots of third-party packages that exist in both .NET and Java ecosystems.

      • Kostas Xaris

        There is the Speedment library for using stream syntax for databases.

  • gacl

    #2: “Developers at Microsoft recommend using a struct in place of a class only for types which are smaller than 16 bytes, are immutable, are short-lived and are not frequently boxed” That is a really narrow use case. The forthcoming Java Project Valhalla, probably will be in Java 10, is delivering much more flexible values types, that will eliminate those limitations. They will be fully usable and efficient with large data as well as small and with long lived objects as well as short lived. And they will require immutability rather than warn against the gotcha scenarios of mutability.

    • Phil Bolduc

      A reason Microsoft’s recommendation is that structs are passed by value as opposed by reference. You can use huge structs, but if you pass it to a function, the runtime has to make a copy of the structure. This could lead to poor performance.

      • gacl

        I agree with your explanation, but that doesn’t change the fact that limiting structs to 16 bytes is a very narrow use case.

        • Phil Bolduc

          There is no limitation in the C# language specification on the size of a struct. You can create a struct that is 1GB in size if you want. It is only a recommendation by Microsoft in their ‘Type Design Guidelines’.

  • gacl

    #3: Async/Await… Java has great non-blocking concurrency options. Notably, they have non-blocking concurrency frameworks like Java. Scala has exactly language features like Async/Await, but using a framework like Akka is still generally preferable.

    • Phil Bolduc

      async/await isn’t about concurrency algorithms like lock free data structures. One of the biggest benefits is preventing threads from being blocked on IO. A thread can do quiet a lot of work while waiting 2 ms for data from redi, database or a API.

      • gacl

        Did you even read what I wrote?

        • Phil Bolduc

          I did read it. However, I believe the article was talking about language features not 3rd party frameworks. Indeed you could add Akka to your project, but that could seem like a big dependency just to read/write asynchronously to a database or file. Akka is a great actor model framework. However, having to understand the actor model and how to use it correctly may be a stretch for some teams. From the Akka I/O documentation: “The I/O API is completely actor based, meaning that all operations are implemented with message passing instead of direct method calls.”

          • gacl

            Yes, Akka is a big dependency and not suitable everywhere. The standard JDK offers non-blocking async file + network APIs, so you can use those directly. The standard JDBC API for SQL databases is blocking, so that is probably a limitation. JVM SQL database libs like Slick provide non-blocking APIs, but I’m not sure the details behind that.

            Also, Scala has async/await type language features, and they aren’t widely used in the JVM world.

          • Phil Bolduc

            I never meant to imply you cannot do async IO in Java. It is just not as easy as using async/await. According to this (like I said I am NOT a Java developer) https://stackoverflow.com/questions/31092067/method-call-to-future-get-blocks-is-that-really-desirable

            Begin Quote:
            Future offers you method isDone() which is not blocking and returns true if computation has completed, false otherwise.

            Future.get() is used to retrieve the result of computation.

            You have a couple of options:

            * call isDone() and if the result is ready ask for it by invoking get(), notice how there is no blocking
            * block indefinitely with get()
            * block for specified timeout with get(long timeout, TimeUnit unit)

            I am sure you can use call backs or Akka or something else to make it cleaner. In my opinion, if a developer could do:

            T result = await getData(); // insert any new fancy keyword instead of ‘await’.

            instead of dealing with isDone(), callbacks? and timeouts.

            I suspect that you are expert Java developer and can write correct async (NIO) code in Java in your sleep. However, not everyone is a good as you and anything that can make it easier and less error prone would be welcome, regardless of the programming language.

            I will leave it up to the other readers to make up their minds. I do not think you and I will see eye-to-eye on this topic. Plus I am biased as a .NET developer.

  • gacl

    All of these reasons are weak. Java should have `var` style type inference like C#/C++/Scala which is actively being added in JEP 286. Java should also have declaration side type variance with generics like C#/Scala which is also actively being added with JEP 300. The active JEPs are actually pretty comprehensive at nailing feature improvements that won’t break backwards compatibility. There are plenty of other improvements that would break backwards compatibility, but you can use Scala or some other language for that.

    • Tali Soroker

      Thank you for your comments. We see a lot of back and forth between the development of these two languages, as a feature is added to one we often see a similar one with additional benefits added to the other. There are many groundbreaking features coming in the next couple of releases of Java, and I’m sure we’ll see many exciting features introduced to C# as well. I’m also looking forward to taking a look at some of the features that Java has pioneered that C# doesn’t have yet in my next post on this subject.

      • Phil Bolduc

        As am I.

    • c_world_poster

      Use Lombok and get var and val

  • kenyee

    Sounds like you want to try Kotlin 😉

  • Andrea Laforgia

    I agree that features like async/await would be convenient, but I disagree that those would be something we’d kill to have 🙂 As you say, many of those C# features can be easily replicated with functional constructs in Java 8 (which is been around for quite a while now, with Java 9 on its way). And if you want to carry out an honest comparison, you have to compare C# with the latest Java versions. I disagree on the necessity to have structs – their presence is, imho, a distortion of object-orientation (an oo language should implement objects as active actors sending message to each other and not mere data-containers). I think the “as” operator is quite dangerous with its implicit conversion to null (null should be banned from any new language). We could continue debating but thanks for taking the effort to write this article 🙂

    • Tali Soroker

      Yes, that MAY have been a slight exaggeration… (: Regardless, thanks for reading and sharing your thoughts!

  • Jonáš Kulhánek

    Missing Expression Trees as it is a great c# feature

  • Diego Visentin

    A very similar async-await for JVM has been developed by Electronic Arts: https://github.com/electronicarts/ea-async
    About LINQ for JVM, there are some projects like http://www.jinq.org and https://www.jooq.org

  • c_world_poster

    Linq from my experience usually makes code difficult to understand and is misused. Honestly, most of the things stated have very little value in most programming situations.

    In 2017, it is all about the frameworks and the JVM beats .NET hands down. FYI … I’ve done .NET since its beginning (and VB classic before that) and Java since 1999.