Skip to content

Data Unit Converter — Java source

Convert between digital data units - B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. Switch between decimal (1000) and binary (1024) bases, runs entirely in your browser.

This is the Java implementation — the same logic the interactive tool runs, in a shareable, citable form.

// =============================================================================
//  DataUnitConverter.java — CosmoDev polyglot showcase port of the
//  `data-unit-converter` tool
//  -----------------------------------------------------------------------------
//  Language : Java (Java 17, standard library only)
//  Source:   ported from src/lib/dataUnits.ts (the canonical, live TypeScript
//             lib); mirrors src/tool-sources/data-unit-converter/{python.py,rust.rs}
//  License  : display source — part of CosmoDev's polyglot tool pages
//             (dev.cosmolabs.org). Shown verbatim alongside the JS/TS/Go/Rust/
//             Python ports and the other language ports.
//  -----------------------------------------------------------------------------
//  Pure digital-data unit conversion. Convert between B, KB/KiB, MB/MiB,
//  GB/GiB, TB/TiB: the decimal base 1000 pairs with KB/MB/GB/TB (SI) and the
//  binary base 1024 with KiB/MiB/GiB/TiB (IEC). Deterministic and
//  side-effect free; convertData returns Double.NaN for non-finite input,
//  unknown unit symbols, or an invalid base — never throws.
// =============================================================================

package org.cosmolabs.cosmodev;

import java.util.List;
import java.util.Map;

/**
 * Pure digital-data unit conversion for the Data Unit Converter tool on
 * CosmoDev (dev.cosmolabs.org).
 */
public final class DataUnitConverter {

    private DataUnitConverter() {
    }

    /**
     * Units available under each base, ordered smallest (B) to largest. The
     * UI uses this to populate the per-base unit pickers. Unmodifiable, like
     * every collection this class exposes.
     */
    private static final Map<Integer, List<String>> UNITS = Map.of(
            1000, List.of("B", "KB", "MB", "GB", "TB"),
            1024, List.of("B", "KiB", "MiB", "GiB", "TiB"));

    /**
     * Power-of-base rank for each unit symbol: "B" is rank 0 and each prefix
     * step adds 1. KB and KiB are both rank 1 — the unit picks the rank, the
     * base decides whether a rank means ×1000 or ×1024.
     */
    private static final Map<String, Integer> EXPONENTS = Map.ofEntries(
            Map.entry("B", 0),
            Map.entry("KB", 1), Map.entry("MB", 2), Map.entry("GB", 3), Map.entry("TB", 4),
            Map.entry("KiB", 1), Map.entry("MiB", 2), Map.entry("GiB", 3), Map.entry("TiB", 4));

    /**
     * Units available under {@code base} (1000 or 1024), ordered smallest to
     * largest, or {@code null} for an invalid base.
     */
    public static List<String> unitsFor(int base) {
        return UNITS.get(base);
    }

    /**
     * Converts a value between two digital-data units under the given base.
     *
     * <p>Strategy: reduce to bytes via {@code value × base^fromExp}, then
     * divide by {@code base^toExp}. Returns {@code Double.NaN} for non-finite
     * input (Inf/NaN), unknown unit symbols, or a base other than 1000/1024 —
     * never throws (mirrors the TypeScript contract).
     *
     * @param value    the magnitude to convert, in {@code fromUnit}
     * @param fromUnit source unit symbol, e.g. "MB"
     * @param toUnit   target unit symbol, e.g. "GiB"
     * @param base     conversion radix: 1000 (decimal/SI) or 1024 (binary/IEC)
     * @return the converted magnitude, or {@code Double.NaN} on invalid input
     */
    public static double convertData(double value, String fromUnit, String toUnit, int base) {
        // Reject Inf/NaN early so they don't propagate through the multiplication.
        if (Double.isNaN(value) || Double.isInfinite(value)) {
            return Double.NaN;
        }
        // Only the two canonical bases are valid; anything else is a caller bug.
        if (base != 1000 && base != 1024) {
            return Double.NaN;
        }
        // Unknown unit symbols miss the map (null) — treat as invalid.
        Integer fromExp = EXPONENTS.get(fromUnit);
        Integer toExp = EXPONENTS.get(toUnit);
        if (fromExp == null || toExp == null) {
            return Double.NaN;
        }

        return (value * Math.pow(base, fromExp)) / Math.pow(base, toExp);
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →