Dart for Java devs

Looking at similarities and differences

Thomas Künneth
Tommis Programming Blog
6 min readApr 13, 2020

--

How much is that in Kelvin?

There are several ways to get your hands on a new programming language. Some prefer reading the language specification. Others like to start with short examples and tutorials. Why not learning by comparing? Let’s try this. Today I will be rewriting a small Java program in Dart. We use a temperature conversion app I wrote for a series of talks about Java on mobile devices. You can find the JavaFX version on GitHub.

Screenshot of a temperature conversion tool written in JavaFX
The JavaFX version running on macOS

The program consists of four classes, a user interface definition and a resource bundle. TemperatureConverter is the main class. It loads the user interface from an fxml file and instantiates a controller class called FXMLDocumentController. This controller binds ui components and actions to a model class named, well, Model. This class holds the actual domain data and invokes code from the Converter class. The converter contains a couple of static methods that do the actual temperature calculation. Let us start with this one.

Converter.java

Although doing different computations, the innards of the methods are mostly the same, that is, doing some arithmetics using the primitive double data type. The method stringToDouble() converts a string to a double value honoring locale specific settings like the decimal mark and the thousands separator. doubleToString() creates a string consisting of a double value with its fractional part omitted if it is zero, and a suffix.

Now, how could we do this in Dart? You might expect that the repo containing the JavaFX version also has a Dart folder. That’s not the case. :-) There, however, is another repo of mine named darttalks. It contains all slides and material for talks I gave about Dart and Dart related topics. It offers two versions of my temperature converter, one for the command line and the web, and one regarding Flutter. For now I will refer to the first one. Under lib/src there is a file called converter.dart.

converter.dart

Possibly to a bit of a surprise, it does not contain a class, but several top level functions. unitDegreesCelsius, unitDegreesFahrenheit and unitKelvin are compile time constants. _f is declared final, so its value can be assigned only once, but obviously not during compile time. I really like the compact function definition using =>, which takes an expression. If more statements are needed, the traditional body using curly braces comes into play. Also very nice is the string interpolation you can see in _doubleToString(). You can access the value of an expression inside a string by using ${expression}. If the expression is an identifier, {} can be omitted. To see the calculations in action I have provided bin/main.dart.

main.dart

The following screenshot shows the execution of the program in Visual Studio Code.

Screenshot of a Dart file being executed in Visual Studio Code
main.dart being executed in Visual Studio Code

So far we looked at two Dart source files, converter.dart and main.dart. Both contained so-called top level functions, that is, making code available without the need to put it in a class. Each Dart file is a library. A library with a top level main() function is called a script. Libraries are combined or grouped to form packages. Packages can be easily distributed and reused. The Dart SDK comes with a package and asset manager called pub. Packages are described in a specification file named pubspec.yaml. It consists of, among other entries, a name, a version and a list of dependencies. For example, Temperature Converter relies on the internationalization package intl. A package can live anywhere. Some packages are on GitHub. Others reside at pub.dev. The pub tool is invoked either through the plugin of your IDE (if you open a pubspec in IntelliJ you get a commands list at the top of the editor window), or from the console. Now, let’s turn to code. Recall that my original temperature converter was written in Java using JavaFX. There is a Model class that uses Converter. So, Model has both state and behavior. The class is used as follows:

  1. Instantiate it
  2. Set the domain data (unit of input and output temperature and the temperature itself)
  3. Perform the calculation
  4. Grab the output string
  5. Go back to 2.

Let’s see how this looks like in Dart.

model.dart

We start with a library statement (which gives the library a name), followed by an import. We rely on the converter library you have encountered in this article. After that you see an enum definition. Compared to, for example Java, Dart enums allow less customization. Currently the string representation of the enum evaluates to enum_name.enum_value. To be able to more easily map user interface elements to enum values (you will see that later) I implemented a convenience method named enumFor(). Dart enums cannot be defined inside classes. Now let’s take a look at the Model class (it’s inside model.dart). Besides the lack of access level modifiers the code looks comfortingly familiar. With two very welcomed exceptions. Have you spotted the get and set keywords? Dart has language level support for getters and setters. To get an idea about how to actually use the Model class, we now take a look at main2.dart. If this script is invoked from the command line, one must pass exactly three arguments:

  1. input temperature unit
  2. value of the input temperature
  3. output temperature unit
main2.dart

The program is quite simple. We have two import statements as we need both model.dart and converter.dart. The first one gives us (among other things) the definition of a class named Model. We instantiate it using the familiar new keyword. After that we set the unit for both input and output temperature. enumFor() is a top-level function defined in model.dart. It checks if one of the enum values ends with the string passed as the only formal parameter. Remember that we pass them to the program via the command line. So to satisfy the string comparison, we need to enter exactly degreesCelsius, degreesFahrenheit or kelvin.

The temperature value itself is converted from String to double through stringToDouble(). This function can be found in converter.dart. It uses an internationalization package named intl. This package is capable of honoring locale-specific settings like the decimal mark and the thousands separator. My example explicitly sets the locale to German, which means that english 1,234.56 has to be entered as 1.234,56. Feel free to experiment with this. Why not reading the name of the locale from the command line? Once the model has been set up, calculateOutTemperature() can be called to do the actual computation. After that, the result can be printed from the getter outTemperatureAsString. Dart has first-class support of getters and setters, so no method parenthesis are needed.

While the command line is a nice start, we surely want some graphical user interface, right? In a future article I will expand on this code and show you how easy it is with Dart to build web applications.

A much less complete version of this article was published as a small series of posts on my Blogger.com blog Tommis Blog. I deleted the weblog in the wake of the GDPR (General Data Protection Regulation), so the original post is no longer available (or only through the Wayback machine of the Internet Archive).

If not stated otherwise images are © Thomas Künneth

--

--

Thomas Künneth
Tommis Programming Blog

Google Developer Expert for Android. Author. Speaker. Listener. Loves writing.