Deephaven's column types
Deephaven tables store data in strongly typed columns. Each column in a table must have a specific type that determines what values it can hold, how much memory it uses, and how operations behave on that column's data. Understanding column types is essential for designing efficient table schemas, writing correct queries, and optimizing performance. This guide covers the column types available in Deephaven tables, how to convert between them, how types behave in table operations, and how to choose the right type for your data.
Column type overview
Deephaven table columns support a rich type system built on Java's type system. The main column type categories are:
| Type category | Examples | Nullable | Memory efficient | Common use cases |
|---|---|---|---|---|
| Primitive numeric | byte, short, int, long, float, double | ✅ (sentinel null values) | ✅ | Numeric calculations, counters, measurements |
| Boolean/char | Boolean, char | ✅ char uses a sentinel null value. Boolean uses Java null. | ✅ | Flags, single characters |
| String | String | ✅ | ⚠️ Each distinct String object takes its own memory. Repeated string literals share one object. | Text data, identifiers, categories |
| Temporal | Instant, ZonedDateTime, LocalDate, LocalTime, Duration | ✅ | ⚠️ Instant is stored as a long. Other temporal types are stored as objects. | Timestamps, dates, times, durations |
| Object | BigDecimal, BigInteger, custom classes | ✅ | ❌ | High-precision math, complex data structures |
| Array | int[], double[], String[] | ✅ (array itself or elements) | ⚠️ Each array is a separate Java object. Primitive arrays store their elements as raw values. | Lists of values, time series |
The rest of this guide explores each of these column types, their properties, and how to use them effectively in your tables. To see how Python and NumPy types map to these Java types, and how type hints and casts set a column's type, see Data types in Deephaven and Python.
Type fundamentals
Numeric primitives, booleans, characters, strings, and temporal (date and time) values are the types most columns use, so understanding them is essential for working effectively with Deephaven tables.
Note
In query strings, string literals go inside backticks, like `Hello`, and char literals go inside single quotes, like 'A'. Backticks work the same way as double quotes in Java. See String and char literals for details.
Primitive numeric types
Primitive numeric types are the most memory-efficient and performant types in Deephaven. They map directly to Java primitives, so each value is stored as a raw number rather than as a separate Java object.
Numeric type reference
| Type | Size | Range | Null value | Example use case |
|---|---|---|---|---|
byte | 8-bit | -127 to 127 | NULL_BYTE | Small integers, status codes |
short | 16-bit | -32,767 to 32,767 | NULL_SHORT | Medium integers, year values |
int | 32-bit | -2³¹+1 to 2³¹-1 | NULL_INT | Standard integers, counters |
long | 64-bit | -2⁶³+1 to 2⁶³-1 | NULL_LONG | Large integers, IDs, nanosecond timestamps |
float | 32-bit | ~±3.4×10³⁸ (about 7 significant digits) | NULL_FLOAT | Approximate decimals, measurements |
double | 64-bit | ~±1.7×10³⁰⁸ (about 15 significant digits) | NULL_DOUBLE | General-purpose decimals, measurements, statistics |
Deephaven reserves the minimum value of each integer type as that type's null value, so the integer ranges above exclude it. For float and double, the null value is the most negative finite value (-Float.MAX_VALUE and -Double.MAX_VALUE).
Creating numeric columns
The examples on this page build values from the special variables i and ii, which hold each row's index as an int and a long. LongCol uses ii because i * 1000000000 would overflow an int.
Null values for primitives
Java primitives can't be null, so Deephaven reserves one value of each numeric primitive type, and of char, to represent null. The numeric types use the values described above, and char uses Character.MAX_VALUE. These reserved values are called sentinel null values. Each type's sentinel has a named null constant, such as NULL_INT and NULL_DOUBLE:
You can check for nulls with isNull or by comparing with the null constant:
float and double columns can also hold NaN, which is a different value from null.
Type promotion and arithmetic
When you do arithmetic with mixed numeric types, Deephaven follows Java's type promotion rules for most operators. Division is different. In query strings, dividing one integer value by another with / returns a double. In Java, int / int truncates instead. To get integer truncation, cast the result explicitly:
Boolean and char
Boolean type
The Boolean type represents true/false values. Boolean columns have the data type java.lang.Boolean. Their null value is Java null, and the null constant NULL_BOOLEAN refers to the same value. Deephaven stores their values compactly as bytes, so they don't carry the per-value cost of the object types. Comparison expressions produce Boolean columns:
Char type
The char type holds a single 16-bit UTF-16 code unit, the same as a Java char:
Note
char is distinct from String. A char column holds single characters, while a String column holds character sequences.
String type
The String type stores text data.
Creating string columns
String operations
Values in a String column are java.lang.String objects, so you can call standard Java String methods on them in query strings:
Strings and memory
Each value in a String column refers to a String object, so a column's memory use depends on how many separate objects it holds. Deephaven doesn't deduplicate (intern) strings that formulas build at runtime:
- A formula that builds strings, such as by concatenation, creates a new
Stringobject for each row, even when values repeat. A column of computed IDs stores one object per row. - A string literal in a formula, such as
`Active`in the example below, is one object shared across rows. A low-cardinality column (one with few distinct values) built from a few string literals stores only a few objects.
Null strings
A null string is different from an empty string:
Temporal types
Deephaven provides robust support for the date and time types in the following table. All of them come from Java's java.time package, and Deephaven's built-in time functions operate on them, which makes them a natural fit for time-series data and temporal analysis. In memory, Instant columns are stored compactly as nanosecond long values. The other temporal types are stored as objects.
Temporal type reference
| Type | Description | Null support | Example value |
|---|---|---|---|
Instant | Point in time (UTC) | ✅ | 2025-01-15T10:30:45.123456789Z |
ZonedDateTime | Date-time with time zone | ✅ | 2025-01-15T10:30:45-05:00[America/New_York] |
LocalDate | Date without time or zone | ✅ | 2025-01-15 |
LocalTime | Time without date or zone | ✅ | 10:30:45.123 |
LocalDateTime | Date-time without zone | ✅ | 2025-01-15T10:30:45 |
Duration | Time-based duration | ✅ | PT5H30M (5 hours, 30 minutes) |
Period | Date-based period | ✅ | P1Y2M3D (1 year, 2 months, 3 days) |
Working with Instant
Instant is the most commonly used temporal type, representing an instantaneous point on the timeline in UTC. Adding or subtracting a number of nanoseconds shifts an Instant, so you can use the built-in nanosecond constants SECOND, MINUTE, HOUR, DAY, and WEEK. Subtracting one Instant from another gives the difference in nanoseconds, and functions such as diffMinutes return it in other units:
Working with ZonedDateTime
Use ZonedDateTime when time zone information is important:
Important
Always pass an explicit time zone when you convert an Instant to a zone-aware or local type. The same Instant has a different local date and hour in each time zone, and daylight saving time transitions shift local clock times, so an assumed zone gives subtly wrong results.
Working with LocalDate and LocalTime
LocalDate and LocalTime are useful for date-only or time-only operations:
Advanced types
For specialized use cases, object and array columns provide flexibility beyond primitive types. Object columns hold any Java object, such as a BigDecimal, and array columns hold several values in each row.
Object types
Common object types include BigDecimal, BigInteger, and custom classes. String and every temporal type except Instant are stored as Java objects too, so the considerations below apply to them as well. This section covers the remaining object types.
Object column considerations
- Performance: Object columns are slower than primitive columns because each value is a separate heap object accessed by reference, and operations on them can't use primitive-specialized code paths.
- Memory: Objects use more memory than primitives because each value carries an object header in addition to its data.
- Null handling: Objects can be Java
nullrather than a sentinel value.
Working with BigDecimal
Use BigDecimal when you need exact decimal arithmetic that double can't provide. The following example creates a BigDecimal column and multiplies it by another BigDecimal. Because BigDecimal isn't imported into query strings by default, the formulas use its full class name:
Array types
Array columns store arrays as values, allowing each cell to contain a list of items. Operations such as group_by produce Deephaven vector columns (for example, IntVector) rather than Java arrays. See Arrays vs. vectors for the differences.
Creating array columns
Working with array columns
Access array elements and properties:
Array null handling
Arrays themselves can be null. Elements of object arrays can be null, and elements of primitive arrays can hold the type's null value (for example, NULL_INT):
Array operations
Deephaven's built-in functions, such as the math functions sum, avg, min, and max, operate on arrays:
Type conversions and casting
The most common ways a numeric or string value changes type are:
- Widening: A numeric value widens to a larger numeric type automatically in arithmetic, as described in Type promotion and arithmetic.
- Narrowing: A numeric value narrows, for example from
doubletoint, only with an explicit cast, and it can lose precision. - Parsing: A string never becomes a number automatically. Convert it with a parsing function such as
parseInt, or with a constructor such asnew java.math.BigDecimal(`1.10`). - Formatting: A number becomes a string when you concatenate it with a string or format it explicitly.
Narrowing with explicit casts
Narrowing conversions need an explicit cast. Casting a double to an integer type truncates the fractional part:
Parsing strings to numbers
Convert strings to numeric types:
Formatting numbers as strings
Convert numbers to strings:
Handling conversion errors
Parsing functions such as parseInt return a null value for a null string, but throw a NumberFormatException for a string that isn't a valid number. Check the string before you parse it:
Using types effectively
Understanding how types behave in table operations helps you write queries that perform well and are easy to maintain. This section shows how column types affect aggregations, joins, and sorts, then gives guidelines for choosing types, keeping queries type-safe, and keeping queries fast.
Aggregations and types
An aggregation's output column doesn't always have its input column's type. The following agg_by example uses three aggregation operators:
agg.sum_returns alongfor anintcolumn and adoublefor adoublecolumn.agg.avgreturns adouble.agg.count_returns along.
Joins and type matching
Joins such as natural_join require matching types in key columns:
Type mismatches cause errors:
Cast to matching types when necessary:
Sorting and type behavior
Sorting orders each column by its type: numbers by value, strings lexicographically, and temporal values chronologically. In an ascending sort, null values come first:
Choose the right type
- Integers: Use the smallest type that fits your range (
byte<short<int<long). - Decimals: Use
doublefor most cases,BigDecimalonly when exact precision is required. - Timestamps: Use
Instantto store points in time, and pass a time zone to functions such astoLocalDateorhourOfDaywhen you need local values. UseZonedDateTimecolumns only when each value must carry its own time zone. - Text: Use
Stringfor text data. Store low-cardinality categories asStringvalues or small integer codes. - Arrays: Use arrays when each row needs multiple related values. Use separate columns instead if you query individual elements often.
Type safety
- Handle nulls explicitly, for example with
isNullor a comparison with the type's null constant. - Use explicit casts when converting between types to make intent clear.
- Match types in join keys. Comparisons between different numeric types work without a cast.
- Test edge cases (nulls, extreme values, type boundaries).
Performance considerations
| Concern | Efficient | Less efficient |
|---|---|---|
| Arithmetic | ✅ int, long, double | ❌ BigDecimal |
| Aggregations | ✅ Numeric primitives | ❌ Objects |
| Memory usage | ✅ Primitives, repeated string literals | ❌ Objects, large arrays |