Slice: byte array access without assembling bytes one at a time
Java library for efficiently working with flat heap memory
At a glance
- What is it?
- Slice is a Java library for reading and writing primitive values inside byte arrays efficiently, with IO stream wrappers, UTF-8 helpers and an explicit little-endian contract enforced through VarHandles and MemorySegment. It suits engineers building file formats, columnar encodings or wire protocols in Java, and its 2.0 rewrite deliberately gave up off-heap memory.
- Who is it for?
- Adopt Slice if you are reading or writing binary formats in Java and the per byte cost of assembling a long or an int is showing up in a profile, because the library removes that cost and keeps the format explicit and documented. Do not adopt it if you need off-heap memory, because that support was removed in version 2.0 and the pre-2.0 releases live on a separate branch.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Slice solves: assembling a long from eight bytes
Slice is a Java library for efficiently working with Java byte arrays. The specific pain it names is reading a `long` at an index without having to assemble the `long` from individual bytes.
That is a real cost in Java, and the reason is structural rather than incidental. A byte array holds bytes, and a long needs eight of them in an order that has to be decided. The straightforward way to do that is a shift and an or per byte, and a shift and an or per byte is a surprising amount of work when you are doing it a few million times while parsing a file. Slice exists to make that operation a single read.
The audience is therefore narrow and technical: engineers implementing file formats, columnar encodings, compressed or packed data, and network protocols, where the code has to touch raw bytes and the cost of touching them is visible. The repository description says it is for efficiently working with flat heap memory, and the README's summary is about Java byte arrays.
It is a library in the plain sense, with no service, no server and no configuration. It is published to Maven Central as `io.airlift:slice`, with a javadoc badge pointing at javadoc.io, and it comes from Airlift, which is the Presto and Trino project's parent project. The licence is Apache-2.0, the default branch is `master`, the last push to the tree was on 2026-09-22, and the release history is 2.9 on 2026-09-22, 2.8 on 2026-06-09 and 2.7 on 2026-03-13, which is a steady quarterly cadence on the 2.x line.
Reading and writing single values, then bulk transfer to primitive arrays
The library's surface has two halves, and the second half is the one that pays at scale.
The first is single value access. In addition to reading and writing single primitive values, Slice provides methods to bulk transfer data to and from primitive arrays. That distinction matters. If you need one long at one offset, a plain shift-and-or is fine. If you need to read ten thousand longs from a buffer, doing it one at a time is a different problem, and the bulk path is what a parser actually wants.
The second half is the set of companion classes described in the IO Streams section. Slice provides classes for interacting with InputStreams and OutputStreams, and those classes support the same fast single primitive access and bulk transfer methods as the Slice class itself. So a parser that reads a length-prefixed block of ints can use the same mental model whether the bytes are already in an array or arriving from a stream, which removes a common source of code duplication in format implementations.
The UTF-8 section is the third area, and it is easy to underestimate. Slice provides a library for interacting with UTF-8 data stored in byte arrays, with functions to count code points, substring, trim, case change, and so on. The reason this is a library rather than a `String` conversion is that going through `String` means decoding the whole buffer into UTF-16, which defeats the point of working in bytes. Counting code points, trimming and changing case directly on the byte representation keeps the work proportional to the bytes you actually touch.
Taken together, the three areas cover the common shape of binary processing in Java: parse a header of primitives, move a payload in bulk, and handle text fields without leaving byte land.
Little-endian by definition, not by accident of the CPU
The byte order section is the most consequential part of the README, and it exists because of a bug class rather than as a design preference.
The library stores multi-byte values in little-endian byte order. The README is explicit that this is distinct from the endianness of the CPU running the code.
Previous versions used `sun.misc.Unsafe` to read and write multi-byte values directly to memory. That bypassed Java's abstractions and assumed the underlying CPU was little-endian. On a big-endian CPU, values would be silently corrupted.
This version uses VarHandles and MemorySegment, which explicitly specify little-endian byte order, and the APIs handle the conversion transparently, so on a big-endian CPU Java automatically swaps bytes when reading or writing. The data format remains little-endian for compatibility, but the library now works correctly on any CPU architecture.
That is a good trade, and it comes with a consequence worth planning around. The on-disk and on-wire format is fixed and documented, and it is little-endian no matter what the machine is. So if you are implementing a format whose specification says big-endian, you cannot use Slice's multi-byte accessors directly for that field. The library solves the portability problem for the format it chose, and it did not solve it for every format.
The hash functions follow the same rule. XxHash64 and Murmur3 also use little-endian byte order, as required by their specifications, so hashing a buffer with Slice produces the same digest as any other correct implementation of those algorithms.
The choice of VarHandles and MemorySegment is also a statement about the platform. Both are APIs of the modern Java memory model, which is a plausible reason the library now requires a recent JDK, and it is why the README contrasts it with `sun.misc.Unsafe`, an internal API that was never meant to be used by libraries.
Getting Slice onto a classpath and making the first read
The repository documents no install command, and that is worth saying plainly rather than inventing one. What it does give you is the distribution coordinates: the Maven Central badge points at the search for the group `io.airlift` and the artifact `slice`, so the dependency is `io.airlift:slice`, and the javadoc badge points at the published API documentation on javadoc.io.
Adding a dependency to a Maven build means declaring that group and artifact in the project's `pom.xml`, and the repository's own `pom.xml` plus the checked in `mvnw` wrapper show how the project itself is built. The `benchmarks.md` file in the repository root is where the measured performance numbers for the operations live, which is the file to read before and after you swap an existing hand rolled reader for the library.
The first use is a single read. You have a `byte[]` and an index, and you want a long out of it in the format the file actually stores, so you call the read method with the array, the offset and the byte order the format specifies, and the library does the byte assembly for you. If the value is a length prefix for a block that follows, the same array and the same offset give you the block boundary, and the bulk transfer method moves the payload into a primitive array without per element work.
Two things are worth checking on that first read. The byte order, because Slice stores little-endian and will not silently convert a big-endian field for you, and the offsets, because the library works on flat byte arrays with explicit indices rather than on structures, so the reader you write is responsible for where each field sits. Slice removes the cost of turning bytes into a primitive. It does not remove the need to know what those bytes mean.
For the wider API, the javadoc on javadoc.io is the reference, and the developer guide for working on the library itself is in the repository's `docs/` directory.
What 2.0 removed: off-heap memory and the legacy branch
The Legacy Slice section documents a removal, and removals are worth reading carefully because they tell you who used to depend on the project.
Version of Slice before 2.0 support off-heap memory and can be backed by any Java primitive array type. These features were rarely used, and were removed in version 2.0 to simplify the codebase. If you need these versions, they are available in the `release-0.x` branch.
So the 2.x line is a heap-only, byte-array-only library, and the older capability is frozen on a side branch with no further work. If your use case was allocating the buffer outside the Java heap to keep it out of garbage collection pressure, that use case is now on a maintenance branch, and the supported line does not do it.
The interesting thing about the removal is the reason given. Rarely used is a usage statistic, and it is a statement that the off-heap feature was carrying complexity that almost nobody was paying for. The simplification benefit is real: without off-heap backing, the class is a byte array and its methods, and the MemorySegment and VarHandle path is uniform rather than having to handle two different memory models. The cost is that the library no longer solves the problem it partly existed for.
The repository root reflects the current state rather than the history. The top level entries are `.github/`, `.gitignore`, `.mvn/`, `LICENSE`, `README.md`, `benchmarks.md`, `mvnw`, `pom.xml` and `src/`. The Maven wrapper is checked in, so a build does not need a system Maven install, and `benchmarks.md` at the root is where the performance numbers live rather than in the README.
Where Slice is the wrong tool, and what to use instead
Three limitations follow from the design.
The first is the fixed byte order, discussed above, and it is a hard constraint rather than a preference. Slice reads and writes little-endian. A format specified in big-endian means either byte swapping by hand, which defeats the point, or a different library.
The second is the removal of off-heap support. If your workload is dominated by large buffers that you want outside the Java heap, current Slice does not do that.
The third is scope. Slice is a byte manipulation library. It does not parse formats, it does not validate, it does not handle endianness negotiation, and it does not give you a schema. If what you need is a way to read a columnar file or a compressed stream, you are going to use something else for the format and possibly Slice underneath it for the primitive reads.
The alternative approach is worth describing precisely, because the difference is one of abstraction level rather than of capability. A higher level library that reads a specific format, whether it is a Java NIO buffer class, a columnar format reader, or a ByteBuffer with an explicit order, handles the primitive access for you and gives you a typed result. The trade is that it only handles the format it knows and the byte order it chose, while Slice gives you a fast primitive read and write at any offset in any byte array you already have, and leaves the interpretation to you.
The other alternative is `ByteBuffer` from the standard library, with an explicit `ByteOrder.LITTLE_ENDIAN` set on it. It does the same job, it is in the JDK, and it does not require a dependency. The differences are that ByteBuffer is a stateful cursor object with a position you have to manage, while Slice is a set of stateless operations on an array with an explicit index, and that the modern MemorySegment API underneath Slice is the same idea expressed in the JDK's own memory model. For a codebase already using ByteBuffer everywhere, switching to Slice for the hot paths is a small change; for a new codebase, it is a choice between one dependency and none.
Editorial conclusion
Adopt Slice if you are reading or writing binary formats in Java and the per byte cost of assembling a long or an int is showing up in a profile, because the library removes that cost and keeps the format explicit and documented. Do not adopt it if you need off-heap memory, because that support was removed in version 2.0 and the pre-2.0 releases live on a separate branch. Before you start, confirm that little-endian is the byte order your format actually uses, since Slice stores multi-byte values that way regardless of the CPU, and check `benchmarks.md` in the repository to see the measured figures for the operations you care about.
Frequently asked questions
What does the Slice Java library do?
Slice is a library for efficiently working with Java byte arrays, providing fast methods such as reading a `long` at an index without assembling it from individual bytes, plus bulk transfer to and from primitive arrays, IO stream wrapper classes with the same access methods, and a UTF-8 helper library for counting code points, substring, trim and case change.
Why did Slice 2.0 replace sun.misc.Unsafe?
Previous versions used `sun.misc.Unsafe` to read and write multi-byte values directly to memory, which bypassed Java's abstractions and assumed a little-endian CPU, so on a big-endian CPU values would be silently corrupted. Version 2.0 uses VarHandles and MemorySegment, which explicitly specify little-endian byte order and swap bytes automatically on a big-endian CPU.
Does Slice 2.0 still support off-heap memory?
No. The pre-2.0 versions supported off-heap memory and could be backed by any Java primitive array type, but those features were rarely used and were removed in version 2.0 to simplify the codebase. The older releases remain available on the `release-0.x` branch.
Where can I get the Slice library?
It is published on Maven Central as `io.airlift:slice`, with javadoc on javadoc.io. The repository itself carries a Maven wrapper script, so building from source does not need a system Maven install, and the performance figures are in `benchmarks.md` at the repository root.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/airlift-slice)Was this useful?