← thecodex.expert · The Codex Family of Knowledge
Tier 0 · Absolute Beginner · Kotlin Project

Temperature Converter

Convert temperatures between Celsius and Fahrenheit. You will learn how a program takes a number, applies a formula, and gives back a result — the essence of almost every useful tool.

🧠 Teaches how to think spoonfed, every age Last verified:

1 The Problem

We want a small program that converts a temperature from Celsius to Fahrenheit, or the other way around. The user picks which direction, types a number, and the program does the maths and shows the answer. Simple — but it teaches the core shape of every calculator-style tool: ask, calculate, show.

Where this shows up in real life: every app that takes a number and transforms it — a currency converter, a tip calculator, a unit converter, a tax estimator — is doing exactly this. Take input, apply a formula, return a result. Master the pattern here and you can build any of them.

2 How to Think About It

Before any code, think about the two things the program needs to know and the two formulas it might use. You do not need Kotlin yet — just the plan:

The plan — in plain English
1. Ask the user which way to convert (Celsius→Fahrenheit, or the reverse). → 2. Ask for the temperature number. → 3. Apply the right formula (C→F is ×9/5 then +32; F→C is −32 then ×5/9). → 4. Show the answer. The only “hard” part is remembering the two formulas — and the program remembers them for you.

1

2

Ask: convert which way?

Choice 1 or 2?

Read Celsius

Read Fahrenheit

Multiply by 9/5, add 32

Subtract 32, multiply by 5/9

Show Fahrenheit

Show Celsius

3 The Build — explained part by part

Here is the complete converter. Read each part’s note below — you should understand the whole thing from the notes alone.

Kotlinconverter.kt
import java.io.PrintStream

/** Converts Celsius to Fahrenheit. */
fun cToF(celsius: Double): Double = celsius * 9 / 5 + 32

/** Converts Fahrenheit to Celsius. */
fun fToC(fahrenheit: Double): Double = (fahrenheit - 32) * 5 / 9

fun main() {
    // Without this, a JVM started under a non-UTF-8 locale (common on bare
    // Linux servers and minimal Docker images) silently turns "°" into "?".
    System.setOut(PrintStream(System.out, true, "UTF-8"))

    println("Temperature Converter")
    println("1. Celsius to Fahrenheit")
    println("2. Fahrenheit to Celsius")
    print("Choose 1 or 2: ")
    val choice = readLine()?.trim()

    when (choice) {
        "1" -> {
            print("Enter temperature in Celsius: ")
            val celsius = readLine()?.trim()?.toDoubleOrNull()
            if (celsius == null) {
                println("Please type a number.")
            } else {
                println("${celsius}°C is ${cToF(celsius)}°F")
            }
        }
        "2" -> {
            print("Enter temperature in Fahrenheit: ")
            val fahrenheit = readLine()?.trim()?.toDoubleOrNull()
            if (fahrenheit == null) {
                println("Please type a number.")
            } else {
                println("${fahrenheit}°F is ${fToC(fahrenheit)}°C")
            }
        }
        else -> println("Please choose 1 or 2.")
    }
}
⚠ No in-browser playground here
Kotlin compiles to real JVM bytecode, not something a browser can run directly — running it live would need either a server-side compiler or a third-party embed, the same kind of external dependency this site avoids relying on for a core teaching example. Copy the code below and run it with a real kotlinc on your own machine instead; the “Run It” section explains exactly how.
What each part does — in plain words
fun cToF / fun fToC — exactly like the Go version, each formula gets its own small, typed function. fun cToF(celsius: Double): Double says “takes a Double, returns a Double” — the compiler checks every call site against that promise, and a single-expression body (= celsius * 9 / 5 + 32) skips the braces entirely.

readLine()?.trim() — Kotlin’s readLine() is a plain, blocking call built into the standard library: no callback, no async iterator, no event to wire up. It returns String? (a nullable string) because input can run out, which is exactly why the ? is there.

?.toDoubleOrNull() — converts the typed text to a number the same way Python’s float() does, except a bad string never throws: it quietly becomes null instead, chained safely through the ?. from the nullable readLine() result.

when (choice) { "1" -> ... } — Kotlin’s when is a more capable switch: each branch can be a whole block, and else plays the role of default.

System.setOut(PrintStream(System.out, true, "UTF-8")) — a defensive line explained fully in “If it breaks” below: without it, the ° symbol silently turns into ? on a JVM started under a non-UTF-8 locale.
Common mistakes — and how to avoid them
✗ Assuming readLine() can never return null, and calling .trim() on it directly.
✓ readLine(): String? is nullable by design — input can run out (end of file). The ?. safe-call operator short-circuits to null instead of crashing when that happens.
✗ Trusting "abc".toDouble() to behave like a safe parse.
✓ Plain toDouble() throws NumberFormatException on bad input. Use toDoubleOrNull(), which returns null instead, and check for that before using the value.
✗ Printing a ° symbol (or any non-ASCII character) and trusting it will always show up correctly.
✓ On a JVM whose locale is not UTF-8-aware (common on bare Linux servers and minimal Docker images), the default console encoding silently replaces it with ?. Setting System.out to an explicit UTF-8 PrintStream at the start of main fixes this regardless of the host's locale — see “If it breaks” below for the real, reproduced bytes.

4 Test & Prove Each Part

How do we know this works? We pull the real logic into small, plain functions and check each one against cases we already know the answer to.

Freezing point: 0°C correctly becomes 32°F
Boiling point: 100°C correctly becomes 212°F
The reverse works: 32°F correctly becomes 0°C
Round-trip: convert there and back, get the original number
Kotlinconverter_test.kt
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class ConverterTest {
    @Test
    fun freezingPoint() {
        assertEquals(32.0, cToF(0.0))
    }

    @Test
    fun boilingPoint() {
        assertEquals(212.0, cToF(100.0))
    }

    @Test
    fun reverseFreezing() {
        assertEquals(0.0, fToC(32.0))
    }

    @Test
    fun roundTrip() {
        assertTrue(Math.abs(fToC(cToF(25.0)) - 25.0) < 0.00001)
    }
}

Compile with kotlinc converter.kt converter_test.kt -include-runtime -d converter.jar (adding kotlin-test.jar and kotlin-test-junit.jar to the classpath) and run with JUnit’s own runner. We pulled the formulas into small, independently-typed functions (cToF, fToC) so the tests can call them directly, without any menu or typed input in the way.

5 The Interface

The program’s interface — what it asks for and what it gives back — documented plainly.

INPUTchoice + temperature1 or 2, then a number
What it expects
Choose 1 or 2: 1
Enter temperature in Celsius: 100
OUTPUTconverted temperaturethe result with units
What it returns
100.0°C is 212.0°F

6 Run It & Automate It

Save the code as converter.kt and compile it with kotlinc converter.kt -include-runtime -d converter.jar, which bundles the Kotlin runtime so the result runs with a plain java -jar.

Run it locally
kotlinc converter.kt -include-runtime -d converter.jar && java -jar converter.jar
Pick a direction, type a temperature, and see the conversion.

A CI tool like Jenkins compiles and tests automatically whenever the code changes — every line below has a plain explanation.

What you should see when it works
Terminala real run
Temperature Converter
1. Celsius to Fahrenheit
2. Fahrenheit to Celsius
Choose 1 or 2: 1
Enter temperature in Celsius: 100
100.0°C is 212.0°F
If it breaks — how to fix it
🚨 100.0?C is 212.0?F — the ° symbol turns into a question mark
This is a real, reproducible bug under a non-UTF-8 locale: run locale in the same shell, and if it prints POSIX or C instead of something ending in UTF-8, the JVM's default console charset cannot represent ° and silently substitutes ? — confirmed on this exact sandbox by inspecting the raw output bytes (0x3F, a literal question mark, not a display artifact). System.setOut(PrintStream(System.out, true, "UTF-8")) at the top of main, as this program does, fixes it for good regardless of the host's locale.
🚨 Please type a number. — even though I typed 100
Check for a trailing space or a stray character from copy-pasting; " 100 ".toDoubleOrNull() is fine once trimmed, but "100cm".toDoubleOrNull() is null.
GroovyJenkinsfile
// Jenkinsfile &mdash; compiles and tests automatically every time the code changes.
pipeline {
    agent any                                  // run on any available machine

    stages {
        stage('Get the code') {
            steps { checkout scm }             // download the latest code
        }
        stage('Set up Kotlin') {
            steps {
                sh 'kotlinc -version'                             // confirm the compiler is installed
            }
        }
        stage('Compile and test') {
            steps {
                sh 'kotlinc converter.kt converter_test.kt -include-runtime -d build.jar'  // one real JVM jar, no build tool required
                sh 'java -cp build.jar:kotlin-test-junit.jar:junit.jar org.junit.runner.JUnitCore ConverterTest'
            }
        }
    }

    post {
        success { echo 'All tests passed.' }
        failure { echo 'A test failed &mdash; look above.' }
    }
}
🎯 Try this next — make it yours

You have a working temperature converter. Extend it:

  1. Add Kelvin. Offer Celsius→Kelvin too (Kelvin = Celsius + 273.15). (Teaches: a third when branch.)
  2. Round differently. Use "%.1f".format(value) for a fixed one-decimal answer. (Teaches: Kotlin's string formatting.)
  3. Keep converting. Wrap the whole thing in a loop so the user can do many conversions without restarting. (Teaches: an outer while (true) loop.)
  4. Guard bad input harder. Instead of giving up on a bad number, loop back and ask again. (Teaches: retry logic with while.)
What you learned
You learned the ask → calculate → show pattern behind every converter and calculator, Kotlin’s nullable types (String?, ?., toDoubleOrNull()) for input that might be missing or malformed, and why console output needs an explicit encoding on some hosts. Related reference: Null Safety & Types, Variables & Types.