Browse Learn Clojure Foundations as a Java Developer

Numbers in Clojure for Java Developers

Learn Clojure's numeric literals, ratios, BigInt and BigDecimal values, overflow behavior, equality rules, and JVM interop concerns without importing Java's primitive-first habits.

Clojure numbers run on the JVM, but they do not feel exactly like Java primitives. Clojure makes exact arithmetic convenient, gives ratios first-class syntax, and lets you choose when to care about primitive performance.

The practical rule is simple: write clear numeric code first, then make type and performance choices where correctness or profiling requires them.

Numeric Literals

Literal Common runtime type Meaning Java mental model
42 java.lang.Long Default integer literal More like long than Java’s default int
42N clojure.lang.BigInt Arbitrary-precision integer Similar role to BigInteger
42M java.math.BigDecimal Decimal literal Similar role to BigDecimal
3.14 java.lang.Double Floating-point literal Java double
22/7 clojure.lang.Ratio Exact fraction No direct Java literal equivalent

Check values at the REPL:

1(map class [42 42N 42M 3.14 22/7])
2;; => (java.lang.Long
3;;     clojure.lang.BigInt
4;;     java.math.BigDecimal
5;;     java.lang.Double
6;;     clojure.lang.Ratio)

For Java developers, the surprise is usually 22/7. It is not truncated integer division and it is not a double. It is an exact ratio.

Integer Division and Exactness

Java integer division truncates:

15 / 2; // => 2

Clojure integer division returns an exact ratio when the result is not integral:

1(/ 5 2)
2;; => 5/2
3
4(double (/ 5 2))
5;; => 2.5

That behavior is useful for exact calculations, but you should convert deliberately when a Java API expects double, float, BigDecimal, or a primitive numeric type.

Overflow and Big Numbers

Do not assume Clojure silently widens all arithmetic. Normal arithmetic operators are checked for primitive overflow:

1(+ Long/MAX_VALUE 1)
2;; ArithmeticException: integer overflow

Use explicit arbitrary-precision values or auto-promoting operators when that is what the domain requires:

1(+ 1N Long/MAX_VALUE)
2;; => 9223372036854775808N
3
4(+' Long/MAX_VALUE 1)
5;; => 9223372036854775808N

Use unchecked math only after measurement and only when overflow behavior is acceptable:

1(unchecked-add Long/MAX_VALUE 1)
2;; => -9223372036854775808

That is a performance tool, not a default application style.

BigDecimal and Money-Like Values

M creates a BigDecimal literal:

1(+ 10.25M 0.75M)
2;; => 11.00M

Use BigDecimal-style values when decimal precision matters, such as money or externally specified decimal quantities. Be careful mixing unsuffixed decimal literals and M literals:

1(+ 10.25M (bigdec "0.75"))
2;; => 11.00M

If your domain is money, prefer integer minor units or consistent BigDecimal handling rather than ad hoc mixing with floating-point values.

Equality Rules That Matter

Clojure has several equality predicates:

Predicate Use for Example
= Value equality (= 1 1N) is true
== Numeric equality (== 1 1.0) is true
identical? Same object or primitive identity Rare in application code

Examples:

1(= 1 1N)
2;; => true
3
4(= 1 1.0)
5;; => false
6
7(== 1 1.0)
8;; => true

Use = for most Clojure data comparisons. Use == when you specifically mean numeric equality across numeric representations.

Java Interop Boundaries

Java methods may require exact primitive or boxed numeric types. Clojure will often coerce at invocation time, but explicit conversion makes intent clearer when ambiguity matters:

1(int 42)
2(long 42)
3(double 22/7)
4(bigdec "10.25")

When performance-sensitive Java interop is involved, type hints can remove reflection:

1(defn elapsed-millis [^java.time.Duration d]
2  (.toMillis d))

Do not scatter hints everywhere. Add them when reflection warnings or profiling show a concrete need.

Choosing Numeric Representation

Need Prefer Why
Normal counts and sizes Long literals Simple and efficient enough for most code
Exact fractions Ratios Preserve exactness through division
Very large integers N literals, bigint, +' Avoid overflow intentionally
Decimal business values BigDecimal or integer minor units Avoid binary floating-point surprises
Scientific or approximate math double Matches JVM numeric libraries
Hot primitive loops Type hints, primitive arrays, unchecked math after profiling Performance work should be measured
    flowchart TD
	    A["Numeric value"] --> B{"Exact integer?"}
	    B -->|Normal range| C["Long"]
	    B -->|May exceed range| D["BigInt or auto-promoting op"]
	    A --> E{"Fractional?"}
	    E -->|Exact ratio| F["Ratio"]
	    E -->|Decimal business value| G["BigDecimal or minor units"]
	    E -->|Approximate math| H["Double"]
	    A --> I{"Java API boundary?"}
	    I -->|Yes| J["convert or type hint deliberately"]

Practice

  1. Evaluate (class 1), (class 1N), (class 1M), and (class 1/3) at the REPL.
  2. Compare (/ 5 2) with (quot 5 2) and explain when each is appropriate.
  3. Write total-cents using integer minor units rather than floating-point dollars.
  4. Trigger an overflow with +, then fix it with +' or N.

Key Takeaways

  • Clojure integer literals default to Long, not Java’s default int.
  • / returns ratios for non-exact integer division.
  • Normal arithmetic is checked for overflow; use big numeric forms deliberately.
  • Use = for general value equality and == for numeric equality across representations.
  • Type conversions and hints belong at Java interop or measured performance boundaries.

Quiz: Numbers in Clojure

### What does `(/ 5 2)` return in Clojure? - [x] The ratio `5/2` - [ ] The integer `2` - [ ] The double `2.5` - [ ] A compiler error > **Explanation:** Clojure returns an exact ratio for non-exact integer division. ### Which literal creates a `BigDecimal` value? - [x] `10.25M` - [ ] `10.25N` - [ ] `10.25L` - [ ] `10.25D` > **Explanation:** The `M` suffix creates a `BigDecimal` literal. ### What should you use when normal integer arithmetic may exceed `Long` range? - [x] Big integer values or auto-promoting operators such as `+'` - [ ] Floating-point numbers by default - [ ] String concatenation - [ ] `identical?` > **Explanation:** Big numeric values or auto-promoting operators make the overflow decision explicit. ### Which predicate is specifically for numeric equality across numeric representations? - [x] `==` - [ ] `identical?` - [ ] `contains?` - [ ] `keyword?` > **Explanation:** `==` compares numeric values across numeric representations. ### True or False: Type hints should be added everywhere in normal Clojure code. - [ ] True - [x] False > **Explanation:** Type hints are useful at interop and performance boundaries, but they should be driven by reflection warnings or profiling.
Revised on Saturday, May 23, 2026