LongBuffer
8 mins
The LongBuffer class is a specialized buffer for 64-bit long integer values, providing efficient storage and manipulation of long data. It’s essential for processing large numerical datasets, timestamps, and 64-bit native data structures.
Source Code #
Core Implementation #
public abstract class LongBuffer extends Buffer implements Comparable<LongBuffer> {
// Factory methods
public static LongBuffer allocate(int capacity) {
return new HeapLongBuffer(capacity, capacity);
}
public static LongBuffer wrap(long[] array) {
return new HeapLongBuffer(array, 0, array.length);
}
public static LongBuffer wrap(long[] array, int offset, int length) {
return new HeapLongBuffer(array, offset, length);
}
// Long operations
public abstract long get();
public abstract long get(int index);
public abstract LongBuffer put(long l);
public abstract LongBuffer put(int index, long l);
// Bulk operations
public LongBuffer get(long[] dst) {
return get(dst, 0, dst.length);
}
public LongBuffer get(long[] dst, int offset, int length) {
checkBounds(offset, length, dst.length);
if (length > remaining())
throw new BufferUnderflowException();
for (int i = offset; i < offset + length; i++)
dst[i] = get();
return this;
}
public LongBuffer put(long[] src) {
return put(src, 0, src.length);
}
public LongBuffer put(long[] src, int offset, int length) {
checkBounds(offset, length, src.length);
if (length > remaining())
throw new BufferOverflowException();
for (int i = offset; i < offset + length; i++)
put(src[i]);
return this;
}
// View operations
public abstract LongBuffer duplicate();
public abstract LongBuffer slice();
public abstract LongBuffer slice(int index, int length);
// Compact operation
public abstract LongBuffer compact();
}
Implementation Details #
64-bit Integer Data Processing #
LongBuffer provides efficient 64-bit integer operations:
// Creating and populating LongBuffer
LongBuffer buffer = LongBuffer.allocate(100);
buffer.put(42L);
buffer.put(10000000000L);
buffer.put(Long.MAX_VALUE);
buffer.flip();
// Reading long integers
long first = buffer.get(); // 42L
long second = buffer.get(); // 10000000000L
long third = buffer.get(2); // Long.MAX_VALUE (absolute get)
// Bulk operations with long arrays
long[] data = {1L, 2L, 3L, 4L, 5L};
LongBuffer wrapped = LongBuffer.wrap(data); // Shares array
long[] copy = new long[5];
buffer.get(copy); // Bulk copy
View from ByteBuffer #
LongBuffer can be created as a view of ByteBuffer (8 bytes per long):
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
// Create LongBuffer view (8 bytes per long)
LongBuffer longBuffer = byteBuffer.asLongBuffer();
// The view shares underlying byte buffer
// Writing to longBuffer affects byteBuffer
longBuffer.put(0, 0x1234567890ABCDEFL); // Writes 8 bytes
longBuffer.put(1, 0xFEDCBA0987654321L); // Writes next 8 bytes
// Byte order critically important for 64-bit values
byteBuffer.order(ByteOrder.BIG_ENDIAN);
LongBuffer bigEndianView = byteBuffer.asLongBuffer();
// Same bytes, completely different interpretation
Compact Operation for Long Data #
public LongBuffer compact() {
int pos = position();
int lim = limit();
int rem = (pos <= lim ? lim - pos : 0);
// Copy remaining longs to beginning
for (int i = 0; i < rem; i++) {
put(i, get(pos + i));
}
position(rem);
limit(capacity());
discardMark();
return this;
}
// Usage pattern for long stream processing
LongBuffer buffer = LongBuffer.allocate(1024);
while (hasMoreData()) {
// Fill buffer with longs
while (buffer.hasRemaining() && hasMoreData()) {
buffer.put(nextLong());
}
buffer.flip();
// Process complete batches
while (buffer.remaining() >= BATCH_SIZE) {
processBatch(buffer);
}
buffer.compact(); // Move remaining data to beginning
}
Performance Characteristics #
| Operation | HeapLongBuffer | DirectLongBuffer (via ByteBuffer) |
|---|---|---|
| Allocation | O(1) fast | O(n) slower (native allocation) |
| Long Access | O(1) direct array access | O(1) with bounds checking |
| Bulk Operations | Fast (System.arraycopy) | Slower (element-by-element) |
| Memory Usage | 8 bytes per long + overhead | 8 bytes per long + native overhead |
| Cache Locality | Good (heap memory) | Variable (depends on allocation) |
Common Patterns #
Timestamp Processing #
// Process streams of timestamp data
LongBuffer processTimestamps(long[] timestamps) {
LongBuffer buffer = LongBuffer.wrap(timestamps);
// Calculate time differences
LongBuffer differences = LongBuffer.allocate(timestamps.length - 1);
for (int i = 1; i < buffer.limit(); i++) {
long diff = buffer.get(i) - buffer.get(i - 1);
differences.put(diff);
}
differences.flip();
return differences;
}
// Filter timestamps within range
long[] filterTimestamps(long[] timestamps, long start, long end) {
LongBuffer buffer = LongBuffer.wrap(timestamps);
LongBuffer filtered = LongBuffer.allocate(timestamps.length);
for (int i = 0; i < buffer.limit(); i++) {
long ts = buffer.get(i);
if (ts >= start && ts <= end) {
filtered.put(ts);
}
}
filtered.flip();
long[] result = new long[filtered.remaining()];
filtered.get(result);
return result;
}
Large Numerical Dataset Processing #
// Process large datasets of 64-bit values
class LongDatasetProcessor {
private LongBuffer buffer;
private long sum = 0;
private long count = 0;
public LongDatasetProcessor(int bufferSize) {
buffer = LongBuffer.allocate(bufferSize);
}
public void processChunk(long[] chunk) {
buffer.put(chunk);
buffer.flip();
// Process chunk
while (buffer.hasRemaining()) {
long value = buffer.get();
sum += value;
count++;
// Additional processing...
}
buffer.clear();
}
public double average() {
return (double) sum / count;
}
}
64-bit Bitmask Operations #
// Process 64-bit bitmasks
LongBuffer processBitmasks(LongBuffer masks) {
LongBuffer result = LongBuffer.allocate(masks.remaining());
while (masks.hasRemaining()) {
long mask = masks.get();
// Common bit operations
long cleared = mask & ~0xFFL; // Clear lower byte
long shifted = mask << 8; // Shift left
long swapped = Long.reverseBytes(mask); // Byte swap
result.put(swapped);
}
result.flip();
return result;
}
// Count set bits in long values
int countSetBits(LongBuffer buffer) {
int total = 0;
for (int i = 0; i < buffer.limit(); i++) {
total += Long.bitCount(buffer.get(i));
}
return total;
}
Native Memory Integration #
// Prepare 64-bit data for native library
LongBuffer prepareNativeLongData(long[] data) {
// Use direct buffer for native access
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(data.length * 8);
byteBuffer.order(ByteOrder.nativeOrder());
LongBuffer longBuffer = byteBuffer.asLongBuffer();
// Copy data to direct buffer
longBuffer.put(data);
longBuffer.flip();
return longBuffer;
}
// Native function expecting pointer to 64-bit integers
native void processLongs(LongBuffer buffer, int count);
// Usage
LongBuffer nativeBuffer = prepareNativeLongData(data);
processLongs(nativeBuffer, data.length);
Best Practices #
Memory Considerations:
- Long values consume 8 bytes each - size buffers appropriately
- For large datasets, consider memory-mapped files
- Monitor native memory usage with direct buffers
Byte Order Sensitivity:
// 64-bit values are highly sensitive to byte order ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // x86 native order LongBuffer longBuffer = byteBuffer.asLongBuffer(); // Always specify byte order explicitlyBulk Operations for Performance:
// Use bulk operations for better performance long[] batch = new long[100]; buffer.get(batch); // Single call vs 100 individual gets // For maximum performance with heap buffers: long[] data = new long[1000]; LongBuffer buffer = LongBuffer.wrap(data); // Zero overhead64-bit Arithmetic Considerations:
// Be careful with 64-bit arithmetic LongBuffer buffer = LongBuffer.allocate(100); // Check for overflow in calculations long a = buffer.get(); long b = buffer.get(); long sum; if (b > 0 ? a > Long.MAX_VALUE - b : a < Long.MIN_VALUE - b) { throw new ArithmeticException("Long overflow"); } sum = a + b;Timestamp-Specific Handling:
// For timestamp data, consider time units LongBuffer timestamps = LongBuffer.allocate(1000); // Convert between units long milliseconds = timestamps.get(); long nanoseconds = milliseconds * 1_000_000L; // Handle epoch conversions Instant instant = Instant.ofEpochMilli(milliseconds);
Common Pitfalls #
- Byte Order Catastrophe: Wrong byte order can completely corrupt 64-bit values
- Memory Consumption: Long buffers consume 8× memory of equivalent byte buffers
- Arithmetic Overflow: 64-bit arithmetic can still overflow in calculations
- Platform Differences: Long size is always 64-bit in Java, but native APIs may differ
- Signed vs Unsigned: Java longs are signed; handle unsigned 64-bit values carefully
- Buffer Position Errors: Forgetting to
flip()between write/read modes - Native Memory Leaks: Direct buffers require careful memory management
Internal Implementation #
HeapLongBuffer #
class HeapLongBuffer extends LongBuffer {
final long[] hb; // The underlying long array
final int offset; // The offset into the array
HeapLongBuffer(int cap, int lim) {
super(-1, 0, lim, cap, null);
hb = new long[cap];
offset = 0;
}
HeapLongBuffer(long[] buf, int off, int len) {
super(-1, off, off + len, buf.length, null);
hb = buf;
offset = 0;
}
public long get() {
return hb[ix(nextGetIndex())];
}
public LongBuffer put(long x) {
hb[ix(nextPutIndex())] = x;
return this;
}
int ix(int i) {
return i + offset;
}
}
DirectLongBuffer (via ByteBuffer view) #
// LongBuffer view of direct ByteBuffer
class ByteBufferAsLongBufferB extends LongBuffer {
private final ByteBuffer bb;
private final int offset;
ByteBufferAsLongBufferB(ByteBuffer bb) {
super(-1, 0, bb.remaining() >> 3, bb.remaining() >> 3);
this.bb = bb.duplicate().order(ByteOrder.BIG_ENDIAN);
this.offset = bb.position();
}
public long get() {
return bb.getLong(ix(nextGetIndex()));
}
public LongBuffer put(long x) {
bb.putLong(ix(nextPutIndex()), x);
return this;
}
int ix(int i) {
return (i << 3) + offset;
}
}
Performance Optimization #
64-bit Data Streaming #
public class LongStreamProcessor {
private LongBuffer buffer;
private final int batchSize;
public LongStreamProcessor(int bufferSize, int batchSize) {
this.buffer = LongBuffer.allocate(bufferSize);
this.batchSize = batchSize;
}
public void processStream(LongSupplier supplier) {
while (true) {
// Fill buffer
while (buffer.hasRemaining()) {
long value = supplier.getAsLong();
if (value == -1L) { // End of stream sentinel
flush();
return;
}
buffer.put(value);
}
// Process full buffer
buffer.flip();
processBatch(buffer);
buffer.clear();
}
}
private void processBatch(LongBuffer batch) {
// Optimized batch processing
long[] temp = new long[batchSize];
while (batch.remaining() >= batchSize) {
batch.get(temp);
// Process temp array...
}
// Handle remaining
if (batch.hasRemaining()) {
long[] remaining = new long[batch.remaining()];
batch.get(remaining);
// Process remaining...
}
}
}
Memory-Mapped Long File Processing #
// Process large long integer file with memory mapping
public void processLongFile(Path filePath) throws IOException {
try (FileChannel channel = FileChannel.open(filePath, StandardOpenOption.READ)) {
long fileSize = channel.size();
// Ensure file size is multiple of 8 bytes
if (fileSize % 8 != 0) {
throw new IOException("File size not aligned to 8 bytes");
}
long position = 0;
while (position < fileSize) {
long size = Math.min(Integer.MAX_VALUE, fileSize - position);
MappedByteBuffer mappedBuffer = channel.map(
FileChannel.MapMode.READ_ONLY, position, size);
mappedBuffer.order(ByteOrder.BIG_ENDIAN);
LongBuffer longBuffer = mappedBuffer.asLongBuffer();
// Process long buffer
processLongBuffer(longBuffer);
position += size;
}
}
}
Long Buffer Pool for High-Throughput #
public class LongBufferPool {
private final ConcurrentMap<Integer, Queue<LongBuffer>> pools =
new ConcurrentHashMap<>();
public LongBuffer acquire(int size) {
Queue<LongBuffer> pool = pools.computeIfAbsent(size,
k -> new ConcurrentLinkedQueue<>());
LongBuffer buffer = pool.poll();
if (buffer == null) {
buffer = LongBuffer.allocate(size);
}
buffer.clear();
return buffer;
}
public void release(LongBuffer buffer) {
buffer.clear();
Queue<LongBuffer> pool = pools.get(buffer.capacity());
if (pool != null) {
pool.offer(buffer);
}
}
}
Related Classes #
- ByteBuffer: Byte buffer with long view support
- IntBuffer: 32-bit integer buffer implementation
- FloatBuffer: 32-bit floating-point buffer
- DoubleBuffer: 64-bit floating-point buffer
- ShortBuffer: 16-bit integer buffer implementation
- MappedByteBuffer: Memory-mapped file buffer