Explain mark(), reset(), rewind(), and remaining()/hasRemaining(), and how they relate to position and limit.
answer
- mark() bookmarks position; reset() jumps back to it
- reset() without mark -> InvalidMarkException
- rewind(): position=0, limit unchanged (re-read)
- flip also sets limit; rewind does not
- remaining() = limit - position; hasRemaining = remaining>0
basics
~20 smark() saves the current position; reset() jumps position back to that saved mark. rewind() sets position to 0 (keeping limit) so you can re-read. remaining() returns limit minus position — the number of elements left — and hasRemaining() is true when remaining() > 0.
solid answer
~50 sThese are the navigation helpers around the position/limit pair. mark() records position into the internal mark field; a later reset() restores position to that mark, letting you peek ahead and back up — but reset() throws InvalidMarkException if no mark is set, and any operation that moves position below the mark (like flip(), rewind(), or clear()) discards the mark. rewind() sets position=0 and clears the mark but leaves limit untouched, so it re-reads exactly the region a prior flip() bounded — the difference from flip(), which also sets limit=position. remaining() is simply limit - position, the count of elements between the cursor and the boundary; hasRemaining() returns remaining() > 0. You use remaining()/hasRemaining() to drive drain loops, mark()/reset() to look ahead during parsing without losing your place, and rewind() to send or scan the same data twice.
go deeper
Knows remaining()/hasRemaining() drive a read loop and that rewind() goes back to the start; may not know mark/reset semantics.
Explains mark()/reset() bookmarking, the InvalidMarkException case, that rewind() leaves limit alone, and computes remaining() as limit-position.
Uses mark/reset for parser backtracking, distinguishes rewind from flip precisely, and knows which operations invalidate the mark.
Reasons about navigation primitives in codec/parser design, the cost and correctness of backtracking, and chooses re-read (rewind) vs. re-frame (flip) deliberately in I/O pipelines.
## The marker invariant Recall the four markers with `0 <= mark <= position <= limit <= capacity`. The methods here read or adjust `position` (and `mark`) without changing `capacity`, and only `flip`/`clear` change `limit` (covered elsewhere). ## mark() and reset() - **mark()** stores the current `position` into the buffer's internal `mark` field and returns the buffer. It is a bookmark. - **reset()** sets `position = mark`. It lets you return to the bookmark after reading ahead. Rules and pitfalls: - If you call `reset()` without a prior `mark()` (or after the mark was invalidated), it throws **InvalidMarkException**. - The mark is **discarded** (set to -1) by any operation that could push position below it: `flip()`, `rewind()`, `clear()`, and setting a position smaller than the current mark. - Typical use: in a parser, `mark()` before tentatively reading a token; if the token doesn't match, `reset()` to retry a different rule (backtracking). ``` buf.mark(); // remember where we are int tag = buf.getInt(); // read ahead if (!isKnown(tag)) { buf.reset(); // back up; position returns to the mark } ``` ## rewind() ``` position = 0; mark = -1; // limit unchanged ``` `rewind()` rewinds the cursor to the start **without touching limit**. That is the key contrast with `flip()`: `flip()` does `limit = position; position = 0`, whereas `rewind()` does only `position = 0`. So `rewind()` is for **re-reading or re-processing the same bounded region** — e.g. after you've written to a channel from a flipped buffer and want to write the same data again, you `rewind()` (not `flip()`, which would shrink limit to 0). ## remaining() and hasRemaining() - **remaining()** returns `limit - position`: the number of elements between the cursor and the boundary — i.e. how many you can still get (read mode) or put (write mode). - **hasRemaining()** returns `remaining() > 0`, i.e. `position < limit`. These drive loops without manual index math: ``` while (buf.hasRemaining()) { consume(buf.get()); } ``` In write mode, `remaining()` tells you how much free space is left before you'd overflow. ## Putting it together | method | effect on position | effect on limit | effect on mark | throws | |---|---|---|---|---| | mark() | unchanged | unchanged | mark = position | — | | reset() | position = mark | unchanged | unchanged | InvalidMarkException if no mark | | rewind() | 0 | unchanged | -1 | — | | flip() | 0 | = old position | -1 | — | | remaining() | unchanged | unchanged | unchanged | — (returns limit-position) | ## Mental model - **mark/reset** = bookmark + jump back (look-ahead/backtracking). - **rewind** = start over within the *same* bounds (re-read/re-send). - **flip** = end writing, start reading (sets the bounds). - **remaining/hasRemaining** = how much is left / are we done.
- What is the difference between rewind() and flip()?Both set position=0 and discard the mark, but flip() also sets limit=position (used after writing, to bound reads), while rewind() leaves limit unchanged (used to re-read/re-send the already-bounded region).
- When does reset() throw, and what invalidates a mark?reset() throws InvalidMarkException if no mark is currently set. The mark is invalidated (set to -1) by flip(), rewind(), clear(), or any setting of position below the mark.
saying these in an interview costs you the question
- Calling reset() without a prior mark() (InvalidMarkException)
- Thinking rewind() resets limit like flip() does
- Assuming mark survives a flip()/clear()/rewind() (it is discarded)
- Confusing remaining() (limit - position) with capacity