Unit converter application I am working on an Android unit converter application, but I came to the point where I have to assign the formulas to the calculation method. At the moment I am using a switch-case statement, as it is more neat than an if-else, but still this proves to be very, very lengthy.

The way the application works is the user selects type of unit to convert, e.g. length. Then 2 spinners show up, one for the "From" unit and one for the "To" unit. On calculation the code picks up what is chosen in the spinners and determines the right formula to use.

Here is a code snippet for only one unit conversion:

switch (unitFrom) {
    case "Kilometers": switch (unitTo){
        case "Miles": initialValue = (initialValue / 1.6);
            break;
        case "Metres": initialValue *= 1000;
            break;
        case "Centimetres": initialValue *= 100000;
            break;
        case "Millimetres": initialValue *= 1000000;
            break;
        case "Feet": initialValue *= 3280.8399;
            break;
        case "Yards": initialValue *= 1093.6133;
            break;
        case "Inches": initialValue *= 39370.0787;
            break;
        case "Nautical Miles": initialValue *= 0.539956803;
            break;
        case "Fathoms": initialValue *= 546.806649;
            break;
        case "Light Years": initialValue *= (1.05702341*(10^-13));
            break;
    }
}


This will become so, so long after just few units being written down, so I was wondering if there's a better way of doing things. I am open to all sort of changes.
The problem with code like this is that it grows very quickly.


switch (unitFrom) {
    case "Kilometers": switch (unitTo){



Adding one unit means that you have to provide conversions to every other unit. But there's a pattern in your code:


    case "Metres": initialValue *= 1000;
        break;
    case "Centimetres": initialValue *= 100000;
        break;
    case "Millimetres": initialValue *= 1000000;
        break;
    case "Feet": initialValue *= 3280.8399;
        break;
    case "Yards": initialValue *= 1093.6133;
        break;
    case "Inches": initialValue *= 39370.0787;



Each unit is essentially just a factor. And the conversion is just the multiplication of the length value with that factor.

Take a look at the SI unit system, where such factors are actually part of the unit:

1 mm = =1 millimeter = 1 * milli * meter = 1 * 10^(-3) * meter


"milli" which would generally be considered part of the unit is actually just a number with a name: 10^(-3)

Notice that the opposite conversion means to divide by that factor.



To simplify the conversion, you can choose a common base unit.
Now you don't have to convert every unit to every other unit but only have to specify one conversion: to/from the base unit.

Here's an example class doing this:

import java.util.HashMap;
import java.util.Set;

public class Converter
{
    public static void main (String[] args)
    {
        Converter converter = new Converter();

        Set&lt;String&gt; units = converter.availableUnits();

        double value = 5.4;

        for (String unitFrom : units)
        {
            System.out.println(value + " " + unitFrom + " are:");

            for (String unitTo : units)
            {
                System.out.println("\t" + converter.convert(unitFrom, unitTo, value) + " " + unitTo);
            }

            System.out.println();
        }
    }

    private HashMap&lt;String, Double&gt; _units;

    public Converter()
    {
        _units = new HashMap&lt;String, Double&gt;();

        _units.put("Millimetres", 1.0);
        _units.put("Metres", 1000.0);
        _units.put("Inches", 25.4);
        _units.put("Feet", 304.8);
        _units.put("Yards", 914.4);
    }

    public double convert(String from, String to, double value)
    {
        return value * _units.get(from) / _units.get(to);
    }

    private Set&lt;String&gt; availableUnits()
    {
        return _units.keySet();
    }
}


The program does every conversion possible.

I kept the conversion from one unit to itself in as a quick test. If you don't want that, opt-out when unitFrom == unitTo.

5.4 Millimetres are:
    5.4 Millimetres
    0.017716535433070866 Feet
    0.21259842519685043 Inches
    0.0054 Metres
    0.005905511811023623 Yards

5.4 Feet are:
    1645.92 Millimetres
    5.4 Feet
    64.80000000000001 Inches
    1.64592 Metres
    1.8 Yards

5.4 Inches are:
    137.16 Millimetres
    0.44999999999999996 Feet
    5.4 Inches
    0.13716 Metres
    0.15 Yards

5.4 Metres are:
    5400.0 Millimetres
    17.716535433070867 Feet
    212.5984251968504 Inches
    5.4 Metres
    5.905511811023622 Yards

5.4 Yards are:
    4937.76 Millimetres
    16.2 Feet
    194.4 Inches
    4.93776 Metres
    5.4 Yards




Additional thoughts:

The name of each unit is only specified once. Retyping string literals is prone to error "Millimetres" != "Millimeters", which the compiler cannot catch.

You could go further and define a class Unit, which besides the name and factor can contain, an abbreviation, plural and singular forms, etc.