Is Flutter likely to replace Java for Android app development?

Java is a fully class-based as well as an object-oriented programming language which is owned by Oracle. Flutter is open source development toolkit based on Dart programming language.

Dart vs C# vs Java

Dart vs C# vs Java

The Dart Language: When Java and C# Aren't Sharp Enough

Originally published by Star Ford at https://www.toptal.com

Way back in 2013, Dart’s official 1.0 release got some press—as with most Google offerings—but not everyone was as eager as Google’s internal teams to create business-critical apps with the Dart language. With its well-thought-out rebuild of Dart 2 five years later, Google seemed to have proven its commitment to the language. Indeed, today it continues to gain traction among developers—especially Java and C# veterans.

The Dart programming language is important for a few reasons:

  • It has the best of both worlds: It’s a compiled, type-safe language (like C# and Java) and a scripting language (like Python and JavaScript) at the same time.
  • It transpiles to JavaScript for use as a web front end.
  • It runs on everything, and compiles to native mobile apps, so you can use it for nearly anything.
  • Dart is similar to C# and Java in syntax, so it’s quick to learn.

Those of us from the C# or Java world of larger enterprise systems already know why type safety, compile-time errors, and linters are important. Many of us are hesitant to adopt a “scripty” language for fear of losing all the structure, speed, accuracy, and debugability that we are used to.

But with Dart development, we don’t have to give up any of that. We can write a mobile app, web client, and back end in the same language—and get all the things we still love about Java and C#!

To that end, let’s walk through some key Dart language examples that would be new to a C# or Java developer, which we’ll sum up in a Dart language PDF at the end.

Note: This article only covers Dart 2.x. Version 1.x wasn’t “fully cooked” - in particular, the type system was advisory (like TypeScript) instead of required (like C# or Java).

1. Code Organization

First, we will get into one of the most significant differences: how code files are organized and referenced.

Source Files, Scope, Namespaces, and Imports

In C#, a collection of classes is compiled to an assembly. Each class has a namespace, and often namespaces reflect the organization of source code in the file system—but in the end, the assembly does not retain any information about the source code file location.

In Java, source files are part of a package and the namespaces usually conform to the file system location, but in the end, a package is just a collection of classes.

So both languages have a way to keep the source code somewhat independent of the file system.

By contrast, in the Dart language, each source file must import everything that it refers to, including your other source files and third-party packages. There are no namespaces in the same way, and you often refer to files via their file system location. Variables and functions can be top-level, not just classes. In these ways, Dart is more script-like.

So you will need to change your thinking from “a collection of classes” to something more like “a sequence of included code files.”

Dart supports both package organization and ad-hoc organization without packages. Let’s start with an example without packages to illustrate the sequence of included files:

// file1.dart
int alice = 1; // top level variable
int barry() => 2; // top level function
var student = Charlie(); // top level variable; Charlie is declared below but that's OK
class Charlie { ... } // top level class
// alice = 2; // top level statement not allowed

// file2.dart
import 'file1.dart'; // causes all of file1 to be in scope
main() {
   print(alice); // 1
}

Everything you refer to in a source file has to be declared or imported within that file, as there is no “project” level and no other way to include other source elements in the scope.

The only use of namespaces in Dart is to give imports a name, and that affects how you refer to the imported code from that file.

// file2.dart
import 'file1.dart' as wonderland;
main() {
   print(wonderland.alice); // 1
}

Packages

The examples above organize code without packages. In order to use packages, code gets organized in a more specific way. Here’s an example package layout for a package named apples:

  • apples/
  • pubspec.yaml—defines the package name, dependencies, and some other things
  • lib/
  • apples.dart—imports and exports; this is the file imported by any consumers of the package
  • src/
  • seeds.dart—all other code here
  • bin/
  • runapples.dart—contains the main function, which is the entry point (if this is a runnable package or includes runnable tools)

Then you can import whole packages instead of individual files:

import 'package:apples';

Nontrivial applications should always be organized as packages. This alleviates a lot of having to repeat file system paths in each referring file; plus, they run faster. It also makes it easy to share your package on pub.dev, where other developers can very easily grab it for their own use. Packages used by your app will cause source code to be copied to your file system, so you can debug as deep into those packages as you wish.

2. Data Types

There are major differences in Dart’s type system to be aware of, regarding nulls, numeric types, collections, and dynamic types.

Nulls Everywhere

Coming from C# or Java, we are used to primitive or value types as distinct from reference or object types. Value types are, in practice, allocated on the stack or in registers, and copies of the value are sent as function parameters. Reference types are instead allocated on the heap, and only pointers to the object are sent as function parameters. Since value types always occupy memory, a value-typed variable cannot be null, and all value-type members must have initialized values.

Dart eliminates that distinction because everything is an object; all types ultimately derive from the type Object. So, this is legal:

int i = null;

In fact, all primitives are implicitly initialized to null. This means you cannot assume that default values of integers are zero as you are used to in C# or Java, and you might need to add null checks.

Interestingly, even Null is a type, and the word null refers to an instance of Null:

print(null.runtimeType); // prints Null

Not As Many Numeric Types

Unlike the familiar assortment of integer types from 8 to 64 bits with signed and unsigned flavors, Dart’s main integer type is just int, a 64-bit value. (There’s also BigInt for very large numbers.)

Since there is no byte array as part of the language syntax, binary file contents can be processed as lists of integers, i.e. List<Int>.

If you’re thinking this must be terribly inefficient, the designers thought of that already. In practice, there are different internal representations depending on the actual integer value used at runtime. The runtime does not allocate heap memory for the int object if it can optimize that away and use a CPU register in unboxed mode. Also, the library byte_data offers UInt8List and some other optimized representations.

Collections

Collections and generics are a lot like what we are used to. The main thing to note is that there are no fixed-size arrays: Just use the List data type wherever you would use an array.

Also, there is syntactic support for initializing three of the collection types:

final a = [1, 2, 3]; // inferred type is List<int>, an array-like ordered collection
final b = {1, 2, 3}; // inferred type is Set<int>, an unordered collection
final c = {'a': 1, 'b': 2}; // inferred type is Map<string, int>, an unordered collection of name-value pairs

So, use the Dart List where you would use a Java array, ArrayList, or Vector; or a C# array or List. Use Set where you would use a Java/C# HashSet. Use Map where you would use a Java HashMap or C# Dictionary.

3. Dynamic and Static Typing

In dynamic languages like JavaScript, Ruby, and Python, you can reference members even if they don’t exist. Here’s a JavaScript example:

var person = {}; // create an empty object
person.name = 'alice'; // add a member to the object
if (person.age < 21) { // refer to a property that is not in the object
 // ...
}

If you run this, person.age will be undefined, but it runs anyway.

Likewise, you can change the type of a variable in JavaScript:

var a = 1; // a is a number
a = 'one'; // a is now a string

By contrast, in Java, you cannot write code like the above because the compiler needs to know the type, and it checks that all operations are legal—even if you use the var keyword:

var b = 1; // a is an int
// b = "one"; // not allowed in Java

Java only allows you to code with static types. (You can use introspection to do some dynamic behavior, but it’s not directly part of the syntax.) JavaScript and some other purely dynamic languages only allow you to code with dynamic types.

The Dart language allows both:

// dart
dynamic a = 1; // a is an int - dynamic typing
a = 'one'; // a is now a string
a.foo(); // we can call a function on a dynamic object, to be resolved at run time
var b = 1; // b is an int - static typing
// b = 'one'; // not allowed in Dart

Dart has the pseudo-type dynamic which causes all the type logic to be handled at runtime. The attempt to call a.foo() will not bother the static analyzer and the code will run, but it will fail at runtime because there is no such method.

C# was originally like Java, and later added dynamic support, so Dart and C# are about the same in this regard.

4. Functions

Function Declaration Syntax

The function syntax in Dart is a little lighter and more fun than in C# or Java. The syntax is any of these:

// functions as declarations
return-type name (parameters) {body}
return-type name (parameters) => expression;

// function expressions (assignable to variables, etc.)
(parameters) {body}
(parameters) => expression

For example:

void printFoo() { print('foo'); };
String embellish(String s) => s.toUpperCase() + '!!';

var printFoo = () { print('foo'); };
var embellish = (String s) => s.toUpperCase() + '!!';

Parameter Passing

Since everything is an object, including primitives like int and String, parameter passing might be confusing. While there is no ref parameter passing like in C#, everything is passed by reference, and the function cannot change the caller’s reference. Since objects are not cloned when passed to functions, a function may change properties of the object. However, that distinction for primitives like int and String is effectively moot since those types are immutable.

var id = 1;
var name = 'alice';
var client = Client();

void foo(int id, String name, Client client) {
       id = 2; // local var points to different int instance
       name = 'bob'; // local var points to different String instance
       client.State = 'AK'; // property of caller's object is changed
}

foo(id, name, client);
// id == 1, name == 'alice', client.State == 'AK'

Optional Parameters

If you’re in the C# or Java worlds, you’ve probably cursed at situations with confusingly overloaded methods like these:

// java
void foo(string arg1) {...}
void foo(int arg1, string arg2) {...}
void foo(string arg1, Client arg2) {...}
// call site:
foo(clientId, input3); // confusing! too easy to misread which overload it is calling

Or with C# optional parameters, there is another kind of confusion:

// c#
void Foo(string arg1, int arg2 = 0) {...}
void Foo(string arg1, int arg3 = 0, int arg2 = 0) {...}

// call site:
Foo("alice", 7); // legal but confusing! too easy to misread which overload it is calling and which parameter binds to argument 7
Foo("alice", arg2: 9); // better

C# does not require naming optional arguments at call sites, so refactoring methods with optional parameters can be dangerous. If some call sites happen to be legal after the refactor, the compiler won’t catch them.

Dart has a safer and very flexible way. First of all, overloaded methods are not supported. Instead, there are two ways to handle optional parameters:

// positional optional parameters
void foo(string arg1, [int arg2 = 0, int arg3 = 0]) {...}

// call site for positional optional parameters
foo('alice'); // legal
foo('alice', 12); // legal
foo('alice', 12, 13); // legal

// named optional parameters
void bar(string arg1, {int arg2 = 0, int arg3 = 0}) {...}
bar('alice'); // legal
bar('alice', arg3: 12); // legal
bar('alice', arg3: 12, arg2: 13); // legal; sequence can vary and names are required

You cannot use both styles in the same function declaration.

async Keyword Position

C# has a confusing position for its async keyword:

Task<int> Foo() {...}
async Task<int> Foo() {...}

This implies the function signature is asynchronous, but really only the function implementation is asynchronous. Either of the above signatures would be a valid implementation of this interface:

interface ICanFoo {
   Task<int> Foo();
}

In the Dart language, async is in a more logical place, denoting the implementation is asynchronous:

Future<int> foo() async {...}

Scope and Closures

Like C# and Java, Dart is lexically scoped. This means a variable declared in a block goes out of scope at the end of the block. So Dart handles closures the same way.

Property syntax

Java popularized the property get/set pattern but the language does not have any special syntax for it:

// java
private String clientName;
public String getClientName() { return clientName; }
public void setClientName(String value}{ clientName = value; }

C# has syntax for it:

// c#
private string clientName;
public string ClientName {
   get { return clientName; }
   set { clientName = value; }
}

Dart has a slightly different syntax supporting properties:

// dart
string _clientName;
string get ClientName => _clientName;
string set ClientName(string s) { _clientName = s; }
5. Constructors

Dart constructors have quite a bit more flexibility than in C# or Java. One nice feature is the ability to name different constructors in the same class:

class Point {
   Point(double x, double y) {...} // default ctor
   Point.asPolar(double angle, double r) {...} // named ctor
}

You can call a default constructor with just the class name: var c = Client();

There are two kinds of shorthand for initializing instance members prior to the constructor body being called:

class Client {
   String _code;
   String _name;
   Client(String this._name) // "this" shorthand for assigning parameter to instance member
       : _code = _name.toUpper() { // special out-of-body place for initializing
       // body
   }
}

Constructors can run superclass constructors and redirect to other constructors in the same class:

Foo.constructor1(int x) : this(x); // redirect to the default ctor in same class; no body allowed
Foo.constructor2(int x) : super.plain(x) {...} // call base class named ctor, then run this body
Foo.constructor3(int x) : _b = x + 1 : super.plain(x) {...} // initialize _b, then call base class ctor, then run this body

Constructors that call other constructors in the same class in Java and C# can get confusing when they both have implementations. In Dart, the limitation that redirecting constructors cannot have a body forces the programmer to make the layers of constructors clearer.

There’s also a factory keyword that allows a function to be used like a constructor, but the implementation is just a regular function. You can use it to return a cached instance or an instance of a derived type:

class Shape {
   factory Shape(int nsides) {
       if (nsides == 4) return Square();
       // etc.
   }
}

var s = Shape(4);

6. Modifiers

In Java and C#, we have access modifiers like private, protected, and public. In Dart, this is drastically simplified: If the member name starts with an underscore, it’s visible everywhere inside the package (including from other classes) and hidden from outside callers; otherwise, it is visible from everywhere. There are no keywords like private to signify visibility.

Another kind of modifier controls changeability: The keywords final and const are for that purpose, but they mean different things:

var a = 1; // a is variable, and can be reassigned later
final b = a + 1; // b is a runtime constant, and can only be assigned once
const c = 3; // c is a compile-time constant
// const d = a + 2; // not allowed because a+2 cannot be resolved at compile time
7. Class Hierarchy

The Dart language supports interfaces, classes, and a kind of multiple inheritance. However, there is no interface keyword; instead, all classes are also interfaces, so you can define an abstract class and then implement it:

abstract class HasDesk {
   bool isDeskMessy(); // no implementation here
}
class Employee implements HasDesk {
   bool isDeskMessy() { ...} // must be implemented here
}

Multiple inheritance is done with a main lineage using the extends keyword, and other classes using the with keyword:

class Employee extends Person with Salaried implements HasDesk {...}

In this declaration, the Employee class derives from Person and Salaried, but Person is the main superclass and Salaried is the mixin (the secondary superclass).

8. Operators

There are some fun and useful Dart operators that we are not used to.

Cascades allow you to use a chaining pattern on anything:

emp ..name = 'Alice' ..supervisor = 'Zoltron' ..hire();

The spread operator allows a collection to be treated as a list of its elements in an initializer:

var smallList = [1, 2];
var bigList = [0, ...smallList, 3, 4]; // [0, 1, 2, 3, 4]
9. Threads

Dart has no threads, which allows it to transpile to JavaScript. It has “isolates” instead, which are more like separate processes, in the sense that they cannot share memory. Since multi-threaded programming is so error-prone, this safety is seen as one of Dart’s advantages. To communicate between isolates, you need to stream data between them; the received objects are copied into the receiving isolate’s memory space.

Develop with the Dart Language: You Can Do This!

If you are a C# or Java developer, what you already know will help you learn the Dart language quickly, since it was designed to be familiar. To that end, we’ve put together a Dart cheat sheet PDF for your reference, specifically focusing on important differences from C# and Java equivalents:

The differences shown in this article combined with your existing knowledge will help you become productive within your first day or two of Dart. Happy coding!

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading about Dart

An introduction to Dart and Flutter

Flutter/Dart - Unit Testing with Mockito

Creating a note-taking app in Flutter/Dart

Dart Programming Tutorial - Full Course

Flutter Tutorial for Beginners - Build iOS & Android Apps w/ Googles Flutter & Dart


Java to C# – C# to Java

Java to C# – C# to Java

In this post, we bring you a much needed Rosetta Stone — an explanatory bridge between these two technologies

Originally published by Andy Macdonald at https://medium.com
Java and C# are incredibly similar. Both languages are somewhat derived from C++ and from similar first principles.

Java was developed in 1995 to create a language with a simpler programming model than C++ while still preserving some of the same syntax of the language to facilitate developers transitioning to it.

C# was developed in 2000 by Microsoft as part of its .NET drive in order to develop a language and set of technologies that could address some of the perceived weaknesses of the C++ language. It was also developed with quite heavy “inspiration” from the Java language.

Despite the similarities between the languages and sharing some common ground, transitioning from one technology to the other for a developer well-practised in one technology can be quite tricky.

Innovation happens best when there is collaboration between people of different mindsets — yet users of C# and Java can be somewhat tribalistic.

To that end, I thought it would be useful to put together a sort of guide to help people thinking about or starting to transition between these two technologies. It would also be nice in some way to facilitate a bit more collaboration between these two worlds — hopefully to do my bit to reduce the needless gulf that exists between them.

Some of the similarities right off the bat:

Java is a language that runs in a virtual machine environment (JVM) and runs bytecode that the Java compiler generates.

For C#, the situation is similar. It is a language that runs on the .NET framework and the CLR runtime. It uses a similar intermediary language to Java bytecode called MSIL which gets run via CLR.

Naming and Conventions

Some of the key and most immediately obvious differences in nomenclature, syntax, and conventions are:

  • “Projects” (Java) — “Solutions” (C#)
  • In Java, methods use lowerCamelCase (bar.doAThing()), whilst in C# public methods use PascalCase (bar.DoAThing())
  • In C#, interfaces are always prefixed with an I, as in IUserService<T>, instead of UserService<T>** **in Java
  • In Java, a string is a String** **— in C# a string is a string
  • “POJO” (Java) — “POCO” (C#)
  • Packages (Java) — Namespaces (C#)

Package (Java)

package dev.andymacdonald;

// Code goes here

Namespace (C#)

namespace Dev.AndyMacdonald 
{
  // Code goes here
}

Syntax

**Java has <strong>final</strong> variables — C# has **<strong>readonly</strong>

A key difference here is that Java final variables can be assigned once anywhere in the class, whereas C#’s readonly variables can only be assigned in the constructor.

C# has <strong>out</strong> and <strong>ref</strong> parameters to allow passing arguments by reference — Java doesn’t

It can manipulate objects and variables by reference, but in a method, these arguments are passed by a value. With C#, we can override this behaviour with the out and ref keywords.

Annotations (Java) — attributes (C#)

These are basically equivalent concepts and just differ in actual syntax. Both annotations and attributes can be accessed via each language’s respective Reflection API implementation.

Java annotation:

@PersonallyIdentifiable
private String fullName;

C# attribute:

[PersonallyIdentifiable]
private string fullName;

Getters and setters or Project Lombok (Java) — C# properties

C# really overtakes Java here with its built-in properties* *feature. In the standard JDK, there isn’t an equivalent to this, and instead, in Java, getters and setters must be written for each field requiring an accessor.

These are often just generated by the developer with their IDE as a cheat … still a bit tedious, though.

Java getters and setters:


public class Element 
{
   
  private String symbol;   
  private String name;   
  private int atomicNumber;
  public int getAtomicNumber() 
  {
    return this.atomicNumber;
  }
  public String getSymbol() 
  {
    return this.symbol;
  }
  public String getName() 
  {
    return this.name; 
  }
  public void setAtomicNumber(int atomicNumber) 
  {
    this.atomicNumber = atomicNumber;
  }
  public void setName(String name) 
  {
    this.name = name;
  }
  public void setSymbol(String symbol) 
  {
    this.symbol = symbol;
  }
}

Many Java projects incorporate Project Lombok, which adds getters, setters, equals, and hash code (plus other useful boilerplates) at compile time.

Project Lombok — not part of the standard library:

@Getter @Setter
public class Element 
{
   
  private String symbol;   
  private String name;   
  private int atomicNumber;
}

C# built-in properties feature:

public class Element 
{

  public string Symbol { get; set; }     
  public string Name { get; set; }     
  public int AtomicNumber { get; set; }
}

Loops

Java for each loop:

List<Integer> fibNumbers = Arrays.asList(0, 1, 1, 2, 3, 5, 8, 13);
int count = 0;
for (int element: fibNumbers)
{
    count++;
    System.out.println(String.format("Element #%s: %s", count, element));
}
System.out.println(String.format("Number of elements: %s", count));

C# for each loop:

var fibNumbers = new List<int> { 0, 1, 1, 2, 3, 5, 8, 13 };
int count = 0;
foreach (int element in fibNumbers)
{
    count++;
    Console.WriteLine($"Element #{count}: {element}");
}
Console.WriteLine($"Number of elements: {count}");

Implementing interfaces/inheritance

Inheritance and implementing interfaces isn’t drastically different between the two languages. Java uses the extends or implements keywords; C# uses C++ syntax (derivation declaration) B : A for defining inheritance.

Defining and implementing an interface with methods in Java:

package dev.andymacdonald;


import java.util.ArrayList;
import java.util.List;

interface Fish
{
   void swim();
}

class Salmon implements Fish
{

   public void swim()
   {
      System.out.println("Salmon.Fish");
   }
}

class Cod implements Fish
{
   public void swim()
   {
      System.out.println("Cod.Swim");
   }
}

public class Program
{
   public static void main()
   {
      List<Fish> fishes = new ArrayList<>();
      fishes.add(new Salmon());
      fishes.add(new Cod());

      for (Fish fish : fishes)
      {
         fish.swim();
      }
   }
}

Defining and implementing an interface with methods in C#:

using System;
using System.Collections.Generic;

namespace Dev.AndyMacdonald 
{
    interface Fish
    {
        void Swim();
    }
    class Salmon : Fish
    {
        public void Swim()
        {
            Console.WriteLine("Salmon.Fish");
        }
    }
    class Cod : Fish
    {
        public void Swim()
        {
            Console.WriteLine("Cod.Swim");
        }
    }
    class Program
    {
        static void Main()
        {
            List<Fish> fishes = new List<Fish>();
            fishes.Add(new Salmon());
            fishes.Add(new Cod());
            foreach (Fish fish in fishes)
            {
                fish.Swim();
            }
        }
    }
}

Pointers

Quite simply, Java just doesn’t do pointers, whereas in C# it is possible to do pointer arithmetic and manipulation.

 unsafe {
  int a = 25;
  int * ptr = &a;
  Console.WriteLine($"Value of pointer is {*ptr}");
}

IDE

Visual Studio

C# developers traditionally and typically use the Visual Studio IDE. This is a situation borne out of the origins of .NET being a closed-source technology. Microsoft developed Visual Studio** **to be a one-stop shop for all things .NET.

Java went down a different route, offering much more developer choice in tooling from the outset. That’s why there’s a much greater range of IDEs for Java development (e.g., IntelliJ, Eclipse, NetBeans). Gradually the landscape for .NET developers has shifted, and more IDEs and developer choice has been offered over the years.

IntelliJ (Java) — Rider (C#)

Users of JetBrains IDEs will find the transition from one IDE to another very smooth if they choose to make a switch to the respective JetBrains IDE in the technology they are targeting. Keyboard shortcuts, IDE layout, and even some plugins are equivalent or comparable — virtually the same IDE.

Dependency Management

Maven (Java) — NuGet and dotnet CLI (C#)

Maven is a tool responsible for dependency management and the life cycle of the building of typically Java and JVM applications. That said, it is pretty flexible, has 1000s of plugins, and can be used to build applications of other languages, such as PHP and JavaScript.

The configurable unit of maven is a pom.xml file that every maven project has. For a project’s submodules, it is possible to have a pom file per submodule which inherits from a parent. Maven uses a remote server or repository of some kind to host and retrieve packages.

Maven pom.xml file (Java):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>dev.andymacdonald</groupId>
    <artifactId>fish-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

At the simplest level, you can test and build a Maven project with the following command:

mvn clean install

And create a package with this:

mvn clean package

And finally, deploy a package like this:

mvn clean deploy

NuGet fulfills a similar, though not identical role in .NET to Maven. NuGet can use a few different configuration files but commonly uses .csproj*. *As with Maven, NuGet uses a server/repository that can host packages.

NuGet .csproj file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <AssemblyName>MSBuildSample</AssemblyName>
    <OutputPath>Bin\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="helloworld.cs" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="MyDependency" version="1.0.0" />
  </ItemGroup>  
  <Target Name="Build">
    <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
    <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
  </Target>
</Project>

NuGet’s primary role is package management, construction, and deployment. Java developers will notice that it doesn’t really have the same concept of build phases as Maven does. Additionally, .NET developers don’t tend to edit their build files manually as Java developers do with pom.xml files, preferring to manipulate them in their IDE instead.

Packages can be built, packaged, and deployed to NuGet with the following nuget commands:

nuget spec
nuget pack {nuspec file}
nuget push {package file} {apikey} -Source {host url}

If you want to run the tests for your .NET application, you can run the following dotnet CLI command:

dotnet test

The dotnet CLI can also be used as a wrapper around nuget commands.

Application Servers

Apache Tomcat (Java) — IIS (ASP.NET)

Tomcat is an open-source web server and servlet container from the Apache Foundation. Though there are many other application servers used widely in Java, it is a pretty common choice for most enterprise-software companies. It works across pretty much every operating system (e.g., Windows, Unix, Linux, and Mac OS).

.NET projects are typically deployed on IIS, a web server that only runs on Windows. While its portability is limited, it’s a pretty popular choice for Windows developers because of its ease of use and simplicity while still offering some advanced configuration options.

… But Wait!

For .NET Core web applications, you can package them to run as standalone web applications — allowing you to run them like this:

dotnet <app_assembly>.dll

In the same way you can run a Java Spring Boot web*** ***application (which has a self-contained Tomcat server):

java -jar <my-application>.jar

And visit your shiny new web app like this:

http://<serveraddress>:<port>

Libraries and Frameworks

Spring Framework (Java) — ASP.NET (C#)

The Spring Framework is a framework and IoC container for Java. In short, the Spring framework is responsible for instantiating objects (beans) and managing the life cycle of these beans in memory.

Create an ApplicationContext* *(similar to the concept of a Startup in ASP.NET). This example uses Spring Boot:

@SpringBootApplication
public class HumanApplication
{
   public static void main(String[] args) 
   {
      SpringApplication.run(HumanApplication.class, args);
   }
}

Create an interface:

public interface Organ<T>
{  
   void function();
}

Implement the Organ<T> interface:

@Component
public class Heart implements Organ<Heart>
{
    public Heart() {}
    public void function() 
    {
        System.out.println("Buh-dump");
    }
}

Constructor injection of Organ dependencies list into a Human service:

@Service
public class Human 
{
    private static final int MAX_SECONDS_OF_LIFE = 3000;
    private List<Organ> organs;
    public Human(List<Organ> organs) 
    {
        this.organs = organs;
    }
    @PostConstruct
    public void live() 
    {
        for (int i = 0; i < MAX_SECONDS_OF_LIFE; i++) 
        {
            organs.forEach(organ -> organ.function());
        }
    }
}

Run the application …

It’s aliiiiiiive:

Buh-dump
Buh-dump
Buh-dump
Buh-dump
...

Spring also ships with a handy suite of modules and packages.

In the core Spring packages, and in the convention-over-configuration extension to the framework, Spring Boot, useful combinations of existing and bespoke technologies are provided for developers wanting access to common libraries to kickstart a project with all that they may need, rather than having to write or track down these utilities themselves:

  • RestTemplate (spring-web — for constructing REST and HTTP requests)
  • JdbcTemplate (spring-data — for constructing JDBC queries and statements)
  • Spring Security (for creating and managing application security models)
  • ObjectMapper (spring-core — useful utility for mapping POJOs from Jackson)
  • etc.

ASP.NET fulfills a similar role in the world of C#, providing IoC functionality, commonly used technologies, and utilities in a single framework. However, ASP.NET generally only provides IoC functionality for web applications, whereas the Spring Framework provides this for any application type.

In terms of dependency inversion, it is possible to do very similar things in ASP.NET as in Spring.

As before, define the needed interface and concrete implementation:

public interface Organ<T>
{  
   void Function();
}
public class Heart : Organ<Heart>
{
    public Heart() {}
    public void Function() 
    {
        Console.WriteLine("Buh-dump");
    }
}

Invoke functions of injected dependencies:

public class Human
{

   private List<IOrgan> _organs;
 
   public Human(List<IOrgan> organs)
   {
      _organs = organs;
      this.Live();
   }
   public void Live()
   {
      organs.ForEach(organ =>
      {
         organ.Function();
      });
   }
}

Define a Startup and register services:

public class Startup  
{    
  public void ConfigureServices(IServiceCollection services)
  {    
    services.AddTransient<IList<IOrgan>>(p => p.GetServices<IOrgan>().ToList());
  }
}

ASP.NET also fulfills the role of providing many useful libraries and utilities to accelerate development of your project.

Streams (Java) — LINQ (C#)

Both Java and C# have mechanisms to simplify the reduction of data sets — Streams and LINQ.

There are some differences and gaps between the two technologies but if you have familiarity with one, you’ll be able to get up and running fairly quickly with the other.

Java Streams:

List<Student> studentList = Arrays.asList( 
    new Student(1, "John", 18, 1),
    new Student(2, "Steve", 21, 1),
);
List<String> studentNames = studentList.stream()
    .filter(s -> s.getAge() > 18)
    .filter(s -> s.getStandardID() > 0)
    .map(s -> s.getName()).collect(Collectors.toList());
studentNames.forEach(name -> System.out.println(name));

LINQ Query (C#):

IList<Student> studentList = new List<Student>() { 
    new Student() { StudentID = 1, StudentName = "John", Age = 18, StandardID = 1 } ,
    new Student() { StudentID = 2, StudentName = "Steve",  Age = 21, StandardID = 1 }
};
var studentNames = studentList.Where(s => s.Age > 18)
                        .Where(st => st.StandardID > 0)
                        .Select(s => s.StudentName);
foreach(var name in studentNames) {   
    Console.WriteLine(name);
}

Apache Commons (Java) — CommonLibrary.NET (C#)

Apache Commons*** ***provides Java developers with a collection of several independently released, useful components and utilities for the purposes of accelerating development.

If you’re in need of a utility to work with ZIP files or a set of utilities for working with mathematical expressions and formulae, then Apache Commons has you covered.

In a similar way, CommonLibrary.NET covers these bases too — there are some key differences in naming of some components and modules, but for the most part, they are pretty much equivalent in their purpose.

That said, unlike Apache Commons, CommonLibrary.NET is quite old and isn’t very commonly used in projects anymore. If you’re after a continuously updated, curated list of libraries for each respective technology, I highly recommend these two lists:

akullpp/awesome-java

quozd/awesome-dotnet

Testing Libraries

JUnit (Java) — NUnit (C#)

Java’s ever-dependable JUnit library has a direct equivalent in C#.

NUnit has almost equivalent functionality to JUnit and is a popular choice for C# developers.

JUnit:

@Test
public void complexNumberTest()
{
    ComplexNumber result = someCalculation();
    Assert.assertEquals("Real", 5.2, result.getRealPart());
    Assert.assertEquals("Imaginary" 3.9, result.getImaginaryPart());
}

NUnit:

[Test]
public void ComplexNumberTest()
{
    ComplexNumber result = SomeCalculation();
    Assert.Multiple(() =>
    {
        Assert.AreEqual(5.2, result.RealPart, "Real");
        Assert.AreEqual(3.9, result.ImaginaryPart, "Imaginary");
    });
}

(Rumour has it NUnit started life as the JUnit source code modified to run in C#.)

Mockito (Java) — Moq (C#)

As with JUnit and NUnit, comparable functionality exists between Java’s Mockito and C#’s Moq library.

Mockito:

Foo mockFoo = mock(Foo.class);
when(mockFoo.doSomething("ping")).thenReturn(true);

Moq:

var mock = new Mock<IFoo>();
mock.Setup(foo => foo.DoSomething("ping")).Returns(true);

That’s It

Thanks for Reading!

I obviously couldn’t fit every difference, similarity, and detail in this article —* *it’s already far too long.

I hope at least I’ve covered enough ground to make you feel confident to make a switch and see how the other half lives.

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

Java Tutorial for Absolute Beginners

100+ Java Interview Questions and Answers In 2019

Python vs Java: Understand Object Oriented Programming

Angular 7 + Spring Boot CRUD Example

Build a Simple CRUD App with Spring Boot and Vue.js