Sitemap
Alexander Obregon

Alexander Obregon

I post daily about programming topics and share what I learn as I go. For recaps, exclusive content, and to support me: https://alexanderobregon.substack.com

Creating a Basic Number Converter with Java

10 min readSep 1, 2025

--

Image Source

Math runs through nearly everything in programming, and Java makes it possible to take a formula on paper and turn it into something that works in code. A simple number converter is a clear way to see how calculations and user input come together to produce results. Converting kilometers to miles or inches to centimeters is basic arithmetic at the surface, but behind it Java manages type safety, reads what the user provides, and executes each formula in a set order.

I publish free articles like this daily, if you want to support my work and get access to exclusive content and weekly recaps, consider subscribing to my Substack.

Building the Logic of a Converter

Java’s type system makes sure numbers are stored in the right way, while its control flow allows developers to pick what kind of conversion to perform. Thinking of it in stages helps. First comes the formula, then the actual math execution, then the way a user provides values, and finally how choices are handled inside the code.

How a Conversion Formula Works

Every unit conversion rests on a constant that links one unit to another. These constants are not random as they come from standardized measurements. For distance, one kilometer equals 0.621371 miles, while one inch equals 2.54 centimeters. To reverse the conversion, you simply use the reciprocal constant. Multiplication or division is all it takes, but having those constants correct is what guarantees that the results are meaningful.

public class DistanceFormulas {
public static double toMiles(double kilometers) {
return kilometers * 0.621371;
}

public static double toKilometers(double miles) {
return miles / 0.621371; // reciprocal used here
}
}

Notice how the second method divides rather than multiplies. Both options are mathematically sound, but in this case dividing by the constant shows another way to write the reverse calculation. Developers often use multiplication for both directions with two different constants, but either style works as long as the ratio is correct.

Not all conversions are direct multiplications. Temperature is a good example of this difference. Converting Celsius to Fahrenheit requires both multiplication and addition, since the scales don’t share the same zero point.

public class TemperatureFormulas {
public static double celsiusToFahrenheit(double celsius) {
return (celsius * 9.0 / 5.0) + 32;
}

public static double fahrenheitToCelsius(double fahrenheit) {
return (fahrenheit - 32) * 5.0 / 9.0;
}
}

This example shows that while many converters rely only on multiplication, some include more than one operation. The important detail is that each formula expresses how two measurement systems relate to each other.

How Java Executes the Math

Java handles conversions through its numeric types, most often double for real-world measurement. When a method like toMiles is called, the input value is stored as a floating point number. Then Java passes that value, along with the constant, to the processor for the multiplication. The CPU instruction runs, and the result comes back as another floating point number. That’s why results are reliable, as long as the inputs and constants are valid.

You can also see how Java promotes types during mixed operations. If you give it an integer, it widens it into a double before performing the multiplication. This promotion step means you don’t need to write extra code to convert whole numbers into decimals yourself.

int kilometers = 5;
double miles = DistanceFormulas.toMiles(kilometers);
System.out.println(miles); // Java automatically widens the int

For this example, the int value 5 becomes 5.0 before the multiplication is executed. The widening happens automatically as part of Java’s type system.

Operator precedence also plays a part in correct results. In the temperature formulas shown earlier, parentheses clarify the order of subtraction and multiplication. Without parentheses, Java would apply multiplication before subtraction, which would produce a wrong result.

double wrong = fahrenheit - 32 * 5.0 / 9.0; // evaluated incorrectly

Parentheses make sure the intended order of operations is preserved, which is an important part of making formulas behave correctly.

Taking Input From the User

A converter is more interesting when a user can provide values rather than having them fixed in code. Java makes this possible with the Scanner class, which reads input typed into the console.

import java.util.Scanner;

public class InputExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);

System.out.print("Enter length in inches: ");
double inches = scanner.nextDouble();

double centimeters = inches * 2.54;
System.out.println(inches + " inches = " + centimeters + " cm");
}
}

The console pauses at the prompt until the user types a number and presses enter. Java translates those characters into a double. If the user enters text that isn’t a number, an exception will be thrown, which is why production code often wraps this step with error handling.

Input can also be taken in string form before converting it to a number. This is slightly more manual, but it shows how parsing works in Java.

System.out.print("Enter distance in kilometers: ");
String input = scanner.nextLine();
double kilometers = Double.parseDouble(input);

This code shows how Double.parseDouble transforms the string into a numeric value. While nextDouble() does this automatically, working with raw strings makes the mechanics clearer.

Handling Different Choices

A real converter usually supports more than one kind of conversion. Instead of hardcoding a single path, you can let the user choose which conversion to run. This is where menus and conditional branching come in.

import java.util.Scanner;

public class ChoiceExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);

System.out.println("Choose type");
System.out.println("1. Kilometers to Miles");
System.out.println("2. Miles to Kilometers");
System.out.println("3. Inches to Centimeters");
System.out.println("4. Centimeters to Inches");
System.out.println("5. Celsius to Fahrenheit");

int choice = scanner.nextInt();
System.out.print("Enter value: ");
double value = scanner.nextDouble();

double result;
if (choice == 1) {
result = DistanceFormulas.toMiles(value);
} else if (choice == 2) {
result = DistanceFormulas.toKilometers(value);
} else if (choice == 3) {
result = value * 2.54;
} else if (choice == 4) {
result = value / 2.54;
} else if (choice == 5) {
result = TemperatureFormulas.celsiusToFahrenheit(value);
} else {
System.out.println("Invalid choice");
return;
}

System.out.println("Converted value: " + result);
}
}

This version uses if statements rather than a switch. The logic is the same, but it shows how conditional flow works by evaluating each condition in order. Whichever condition matches first is executed, and the rest are skipped.

Menus like this reflect how users interact with converters in practice. The input is read, the choice is compared against expected values, and then the matching formula is executed. That flow shows how decision making is built into Java through branching logic.

Mechanics Behind User Interaction and Program Flow

After building the formulas and letting the user select conversions, the next layer of detail is how Java manages those interactions behind the scenes. Input has to be parsed into numbers, method calls have to be tracked in memory, and floating point values are handled with rules that explain why results sometimes look slightly different from what’s written on paper. Together, these mechanics show how a small converter runs with accuracy and structure.

Input Parsing in Java

When a user types into the console, what arrives in Java first is a sequence of characters. Scanner.nextDouble() turns what’s typed into a numeric value, but it follows the JVM’s default Locale. That means the decimal separator could be a comma in some locales and a period in others. If the input doesn’t match the expected numeric format, InputMismatchException is thrown. End of input produces NoSuchElementException, and a closed scanner produces IllegalStateException.

A closer look at Double.parseDouble() reveals the process more clearly. That method reads a string and converts it into a double using rules defined by the IEEE 754 floating point standard. The digits are broken into an integer part, a fractional part, and an optional exponent if one is included.

String value = "123.45";
double number = Double.parseDouble(value);
System.out.println(number); // prints 123.45

Here we see the conversion from text into a usable number. Both perform numeric parsing, though Double.parseDouble ignores the default Locale and always expects . as the decimal separator, while Scanner.nextDouble() is locale aware.

Get Alexander Obregon’s stories in your inbox

Join Medium for free to get updates from this writer.

Parsing also allows inputs in scientific notation, which is worth noting when working with very large or very small measurements.

String scientific = "1.2e3"; // 1.2 × 10^3
double parsed = Double.parseDouble(scientific);
System.out.println(parsed); // prints 1200.0

A converter that accepts typed values benefits from this, since users aren’t limited to plain decimal numbers.

Function Calls on the Stack

Each time a conversion method is called, Java creates a new stack frame to store the method’s parameters and any local variables. This stack is managed by the JVM and grows or shrinks as methods are entered and exited. After the method finishes, the stack frame is discarded, and control returns to the point that made the call.

You can see this in action by chaining a call from one method to another.

public class StackExample {
public static void main(String[] args) {
double miles = convertDistance(8.0);
System.out.println("Result: " + miles);
}

public static double convertDistance(double kilometers) {
return multiply(kilometers, 0.621371);
}

public static double multiply(double value, double factor) {
return value * factor;
}
}

main calls convertDistance, which in turn calls multiply. At runtime, three stack frames exist at once: one for main, one for convertDistance, and one for multiply. When multiply completes, its frame is removed. Then convertDistance returns, and finally control is back with main. This layering of frames is how Java keeps method calls isolated from each other.

Recursive functions demonstrate this even more clearly because they create multiple frames of the same method. Although recursion isn’t usually required for a number converter, it shows how stack growth works.

public static int factorial(int n) {
if (n == 0) return 1;
return n * factorial(n - 1);
}

Every call to factorial makes a new frame until n reaches zero, at which point the frames begin returning one by one. The stack handles this entire sequence automatically.

Floating Point Precision

Working with measurements means dealing with floating point numbers, and that comes with limits. Some decimal values can’t be represented exactly in binary, which explains why results sometimes include a very small rounding error.

double result = 2.2 * 0.621371;
System.out.println(result);

Instead of printing a tidy value, the output may include an extra fraction of a digit. This isn’t because the math was wrong but because the binary floating point format can’t hold some decimal fractions exactly.

Java follows the IEEE 754 standard, which defines how floating point numbers are stored as sign, exponent, and mantissa bits. A consequence of this format is that operations may include tiny rounding differences. When precision is critical, Java’s BigDecimal class can be used. It represents numbers as arbitrary precision decimals rather than binary fractions.

import java.math.BigDecimal;

BigDecimal kilometers = new BigDecimal("2.2");
BigDecimal factor = new BigDecimal("0.621371");
BigDecimal miles = kilometers.multiply(factor);
System.out.println(miles); // prints exact value

While BigDecimal provides exact arithmetic, it’s slower and more memory heavy. For most converters, double is the right choice, as the differences are too small to matter in daily use.

Program Flow Control

Program flow determines the path a converter takes from reading input to printing results. Java executes statements one at a time, branching when conditional checks are met, looping when repeated actions are required, and returning to earlier points when methods are called.

A simplified trace of flow in a converter shows this clearly.

Scanner scanner = new Scanner(System.in);

System.out.print("Enter kilometers: ");
double km = scanner.nextDouble();

if (km > 0) {
double miles = km * 0.621371;
System.out.println("Miles: " + miles);
} else {
System.out.println("Value must be positive");
}

Execution begins at the input statement, then moves to the conditional check. If the value is greater than zero, the multiplication is run, and the result is printed. If not, the alternate branch is executed.

Flow control also manages loops, which can be added to let the user perform multiple conversions without restarting the program.

boolean running = true;
while (running) {
System.out.print("Enter kilometers (0 to quit): ");
double km = scanner.nextDouble();

if (km == 0) {
running = false;
} else {
double miles = km * 0.621371;
System.out.println("Miles: " + miles);
}
}

The loop continues until the user enters zero. Java evaluates the condition at the top of the loop and decides whether to keep running or exit. This shows how branching and looping work together to guide the overall path of the program.

ApexConverter as a Full Unit Converter

A project worth checking out is ApexConverter.com, mentioned by a reader. It’s a unit converter built with Java that covers an extensive range of measurements, pulling from global standards for accuracy. Instead of handling only a handful of conversions, it offers a broad library that spans distance, weight, temperature, and much more, making it far more complete than the small converters used as teaching examples.

What makes it interesting is how directly it connects with the ideas covered throughout this article. The same formulas, type handling, and flow control that go into a basic converter are there, but scaled into something that feels ready for daily use. Trying it out gives a strong sense of how Java’s mechanics with input, math, and branching grow into a polished tool that can handle almost any conversion someone needs. It reinforces the point that the small steps practiced here are the very same ones that drive larger tools built for real-world use.

Conclusion

Building a number converter shows more than unit formulas on paper. It reveals how Java takes user input, parses it into values, stores and manages them through stack frames, and applies floating point rules to carry out the math. Even a small converter demonstrates the path from typed text to calculated result, with control flow guiding each step. These mechanics are the same ones that support larger applications, which makes a simple converter a clear way to see Java at work.

  1. Java SE Documentation
  2. Scanner Class Docs
  3. Double Class Docs
  4. BigDecimal Class Docs
  5. Java Control Flow Statements
  6. ApexConverter.com

Thanks for reading! If you found this helpful, highlighting, clapping, or leaving a comment really helps me out.

--

--

Written by Alexander Obregon

I post daily about programming topics and share what I learn as I go. For recaps, exclusive content, and to support me: https://alexanderobregon.substack.com