Everything a Java Developer Needs to Know About C#

Many computer science students learn Java as their first language in college courses — it’s a classic for a reason. But, once you’ve graduated and stepped into the world of professional software development, you’ll probably need to pick up a few other languages pretty quickly. Luckily, if you’re asked to learn C#, it’s incredibly easy to dive into if you have a background in Java.

Syntax

Java and C# are both in the C family of programming languages, so they naturally have much in common. The C# syntax will look really familiar to you if you’ve spent time with Java.

C# is an object-oriented language, so you will find yourself writing many classes. These are declared the same way as in Java. Methods and variables are also declared the same way, and you can use the same types of if statements and loops.

For a concrete example of the similarity between these two languages, let’s look at a program that handles visiting a farmer’s market.

You might write something like this in Java:


package farmers.market;

public class FarmersMarket {
  private final ShoppingCart shoppingCart;

  public FarmersMarket(ShoppingCart shoppingCart) {
    this.shoppingCart = shoppingCart;
  }

  public void visitBananaVendor(boolean needBananas, int numToBuy) {
    sayToVendor(“Good morning!”);
    if (needBananas) {
      sayToVendor("I'll take " + numToBuy + " bananas.");
      shoppingCart.addBananas(numToBuy);
    } else {
      sayToVendor(“They look delicious but I don’t need any today.”);
    }
  }

  public void visitBananaVendorWithoutBuyingAny() {
    visitBananaVendor(false, 0);
  }

  private void sayToVendor(String message) {
    System.out.println(message);
  }

  public static void main(String[] args) {
    var farmersMarket = new FarmersMarket(new ShoppingCart());
    var today = LocalDate.now();
    var dayName = today.getDayOfWeek()
        .getDisplayName(TextStyle.FULL, Locale.getDefault());
    if (dayName.equals("Monday")) {
      farmersMarket.visitBananaVendor(true, 5);
    } else {
      farmersMarket.visitBananaVendorWithoutBuyingAny();
    }
  }
}

If someone asked you to rewrite your program in C#, it looks nearly identical:


namespace Farmers.Market
{
  public class FarmersMarket
  {
    private readonly ShoppingCart _shoppingCart;

    public FarmersMarket(ShoppingCart shoppingCart)
    {
      _shoppingCart = shoppingCart;
    }

    public void VisitBananaVendor(bool needBananas, int numToBuy = 0)
    {
      SayToVendor(“Good morning!”);
      if (needBananas)
      {
        sayToVendor($"I'll take {numToBuy} bananas.");
        shoppingCart.AddBananas(numToBuy);
      }
      else
      {
        SayToVendor(“They look delicious but I don’t need any today.”);
      }
    }

    private void SayToVendor(string message)
    {
      Console.WriteLine(message);
    }

    public static void Main(string[] args)
    {
      var farmersMarket = new FarmersMarket(new ShoppingCart());
      if (DateTime.Now.DayOfWeek == DayOfWeek.Monday) {
        farmersMarket.visitBananaVendor(needBananas: true, 5);
      } else {
        farmersMarket.visitBananaVendor(needBananas: false);
      }
    }
  }
}

C# has some different coding conventions. Those include using Pascal case for method names instead of camel case and putting curly brackets on their own lines. Some of the built-in types also have slightly different names in C#. For example, String in Java is string in C#, and boolean in Java is bool in C#. You’ll find some other small differences, but nothing too odd or unintuitive.

Shortcuts in C#

You might have noticed in the above example that we need an extra method in Java for when the shopper doesn’t want to buy any bananas. In the C# code, we combine default values and named parameters to get the same readability for the method call without the need to write that extra method.

This is just one of several features any Java developer will immediately appreciate: the ability to write less code while still getting the behavior you need.

Another easy shortcut in C# is its built-in string interpolation. The long way is concatenating string literals and variables or using String.format() and providing your variables as separate parameters. Instead, you can simply prefix the string literal with $ and then use curly brackets to insert your variables.

Here’s a common Java scenario. You need to return multiple pieces of data from a method, but you don’t already have a class that encapsulates that particular set of data. And, you don’t foresee needing it anywhere else in your code. You often end up writing a private static class to hold those pieces of data and return them together from your method. Or, you might end up adding a dependency on a library with tuple support. C# has built-in support for tuples, and you can even name the values in the tuple:


private (double price, int numAvailable, string description) GetProductInformation()
{
  return (price: 1.50, numAvailable: 26, description: "A beautiful yellow fruit.")
}

Another annoyance when working with Java is finding yourself Googling “how to convert java array to list.” It’s not a difficult task, but it always takes more code than you want it to. You never lose hope that someone might have discovered a nicer way to do it in one line. C# once again has your back here, with convenient built-in support for iterating over arrays and converting them to lists:


var upperCaseFruits = new string[] { "apple", "orange", "banana" }
    .Select(fruit => fruit.ToUpper()).ToList();

Threading

Writing asynchronous code in Java can be tricky. Say you need to execute some work in parallel and then wait for it all to finish before proceeding. In that case, you often end up with some ugly code where you not only have to create new threads to execute the work but also handle keeping track of when the work is done:


public List<Data> fetchData(List<DataSource> dataSources) {
  var result = new ArrayList<Data>();
  var countDownLatch = new CountDownLatch(dataSources.size());

  for (DataSource dataSource : dataSources) {
    var thread = new Thread(() -> {
      result.add(dataSource.getData());
      countDownLatch.countDown();
    });
    thread.start();
  }

  // if we have 5 items in dataSources, this will cause the current 
  // thread to wait until countDownLatch.countDown() is called 5 times
  countDownLatch.await();
  return result;
}

In C#, you can declare the method as async and then use the await keyword. Here, we have mapped each data source to a Task that handles fetching the data, and we use Task.WhenAll to wait for each task in the list to finish executing. There’s no need to notify any counters about when the work is done, and we can also map the results directly into a variable instead of adding them to a list.


public async Task FetchData(List dataSources) {
  var result = await Task.WhenAll(
    dataSources.Select(dataSource => Task.Run(dataSource.GetData))
  );
  return result.ToList();
}

Resources

You’re well prepared to start working on a C# project, but you’ll probably still hit some stumbling blocks once you get started.

  • The Microsoft C# docs are great for both API documentation and understanding the language more deeply.
  • If you’ve used IntelliJ to write Java, you can jumpstart your productivity in C# by using Rider and selecting the IntelliJ Keymap.
  • You’ll also want to learn about NuGet so you can use packages in your projects, just like you would use Maven with a Java project.
Conversation

Join the conversation

Your email address will not be published. Required fields are marked *