Implementation of a RingBuffer in Java with optional FIFO like semantics
12 comments
·February 5, 2025stickfigure
final RingBuffer<String> ringBuffer = new RingBuffer<>(String.class, capacity);
Why does the constructor need the Class<?> parameter?jcrites
Looking at the source, I don't think there's an actual need for the constructor to take a `Class<T>` type. It's used internally to initialize an array [1]:
this.entries = (T[]) Array.newInstance(type, capacity);
However, I think this alternative would work equally well, and would not require a `Class<T>` parameter: this.entries = (T[]) new Object[capacity];
There are some other choices in the library that I don't understand, such as the choice to have a static constructor with this signature: public static RingBuffer<Object> create(final int capacity) {
return create(capacity, false);
}
This returns the type `RingBuffer<Object>`, which isn't as useful as it could be; with appropriate idiomatic use of generics it could return a `RingBuffer<T>`: public static <T> RingBuffer<T> create(final int capacity, final boolean orderedReads) {
return new RingBuffer<>(capacity, orderedReads);
}
It's possible that this code was written by someone who is still learning idiomatic Java style, or effective use of generics.I'm also curious about the choice to have `get()` return `null`. I think I'd rather have seen this modeled with `Optional`. My preferred style when writing Java code is to employ non-nullable references wherever possible (though the return from `get()` is marked `@Nullable` at least).
[1] https://github.com/evolvedbinary/j8cu/blob/94d64cfc0ec49a340...
o11c
That's about the least-bad thing about the code here - it's a workaround for the fact that Java lacks runtime support for generics.
Other than its indirect use in `copy` (which in Java normally takes the parameter itself), it's probably not actually necessary here since you could just use `Object[]`? But I don't spend enough time in Java (thankfully) so I'm not sure if there are intricacies involving the runtime overhead of casting.
IncreasePosts
Line 115: this.entries = (T[]) Array.newInstance(type, capacity)
You can't just say new T[capacity] in java.
jcrites
True, but you can say `new Object[capacity]` and cast it to type `T[]`.
hoppp
Targeting java 8... Last updated 5 days ago... What... Stuck forever at java 8?
cosmotic
If it doesn't use any new features then there's no reason to target anything newer, and you'd just be restricting who could use the library.
tracer4201
[dead]
PaulHoule
Can't you get either behavior out of a Deque?
n1b0m
A deque is an abstract data type, because it is defined by what you can do with it; what operations it supports. You can add and remove elements at either end of a deque.
A RingBuffer is a data structure, because it defined by how it is represented in memory, and how its state should be manipulated to fulfil the deque operations.
PaulHoule
I looked at the source. Is it right that it overwrites when it reaches full capacity? That's scary!
Aren't there concurrent versions of this that block writers until space frees up?
This implementation should be avoided; it is weird, buggy, and unnecessarily complicated.
In particular, using some pseudocode to simplify:
I haven't looked for bugs with orderedReads=true (besides the obvious memory leak), but given the footguns and unnecessarily complications this should be avoided regardless.