Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java ByteBuffer flip and compact: preserve an incomplete frame

Last updated: 4 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

ByteBuffer.flip changes a buffer from writing to reading, while compact moves unread bytes to the front for the next write cycle.

Carry unfinished input across reads

A stream chunk may end halfway through a record. After flip, consume only complete records; compact retains the unread suffix and sets the position after it. The next chunk appends there. Clearing the buffer would discard the partial record, while flipping twice without a write would distort the limit.

This three-byte record arrives in two chunks. The parser waits until all three bytes are present. Short reads explain why chunk boundaries cannot be treated as message boundaries.

Cap the record format

A fixed buffer works only if the largest accepted record fits. For variable-length frames, reject oversize declarations or move to a bounded spill strategy before compact can leave the buffer permanently full. Byte order matters when a frame contains multibyte numeric fields.

Working program

Java
import java.nio.ByteBuffer;

public class DispatchFrameAccumulator {
    static void accept(ByteBuffer pending, byte[] chunk) {
        pending.put(chunk);
        pending.flip();
        while (pending.remaining() >= 3) {
            int site = pending.get() & 255;
            int quantity = pending.get() & 255;
            int checksum = pending.get() & 255;
            System.out.println(site + ":" + quantity + ":" + checksum);
        }
        pending.compact();
    }

    public static void main(String[] args) {
        ByteBuffer pending = ByteBuffer.allocate(6);
        accept(pending, new byte[] {47, 2});
        System.out.println("pending=" + pending.position());
        accept(pending, new byte[] {49, 82, 3, 85});
        System.out.println("pending=" + pending.position());
    }
}

Output

Output
pending=2
47:2:49
82:3:85
pending=0

Cost and ownership

Each complete three-byte frame is parsed once. compact copies the unread suffix, so repeated compaction of a large partial record can add copy cost; a size cap and chunk plan keep that cost predictable. The buffer owns six bytes here.

Common Mistakes

  • Do not call clear when unread bytes must survive.
  • Do not parse a record merely because a transport read ended.
  • Do not call put when the buffer lacks space for the next chunk.

Read next

Java InputStream short reads: assemble a complete record header, Java ByteBuffer byte order: decode the protocol before reading integers, bytebuffer slice ownership, Java file channels: buffer positions and partial transfers.

Continue with: Java FileChannel.write: finish the buffer before reporting success, Java AsynchronousFileChannel: own the buffer through completion.

java
io
bytebuffer-flip-compact-state
Storage details