java nio中mark()和reset()用于轻量级位置回退:mark()保存当前position到mark字段,reset()将position恢复为mark值,需满足mark≤position≤limit≤capacity且mark未被clear()/flip()等操作重置为-1。

Java NIO 中的 mark() 和 reset() 方法,是为了解决“某段已读数据需要再次读取”这一常见需求而设计的。它们不改变缓冲区内容,只操作 position 和 mark 这两个指针,实现轻量级的位置回退。
mark() 和 reset() 的作用机制
mark() 会把当前 position 的值保存到 mark 字段中(mark = position);reset() 则把 position 恢复为之前标记的值(position = mark)。前提是 mark 已被设置且未被丢弃(比如调用 clear() 或 flip() 会重置 mark = -1)。
二者必须成对使用,且中间不能有使 mark 失效的操作。关键约束是:mark ≤ position ≤ limit ≤ capacity,违反时会抛出 InvalidMarkException。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
适用场景:重复解析同一段数据
典型例子包括协议解析中“先 peek 再决定如何处理”——比如读到几个字节后判断是否为某种消息头,若不是则退回重试;或解析 JSON/HTTP 前缀时需多次检查字段边界。
- 在读取过程中调用
buffer.mark()记录起始位置 - 继续读取若干字节做试探性解析
- 若不符合预期,调用
buffer.reset()回到标记点,重新尝试其他逻辑 - 若已确认格式,可继续读后续内容,或调用
buffer.mark()设置新标记
一个实用示例:跳过空格后尝试读整数
假设从 ByteBuffer 中读取一段含前导空格的数字字符串,希望跳过空格后尝试解析为 int,失败则恢复位置供后续处理:
buffer.mark(); // 标记当前位置(可能是空格开头)
while (buffer.hasRemaining() && buffer.get() == ' ') {
// 跳过空格
}
buffer.reset(); // 无论跳了多少个空格,都回到原始起点
// 现在从头开始,用更稳健的方式解析:例如转为 String 后 parse
int len = buffer.remaining();
byte[] arr = new byte[len];
buffer.get(arr);
String s = new String(arr, StandardCharsets.US_ASCII);
try {
int num = Integer.parseInt(s.trim());
} catch (NumberFormatException e) {
// 解析失败,但原始 buffer 位置未被破坏,可交由其他逻辑处理
}
注意事项与常见陷阱
mark 不是持久状态,很多 Buffer 操作会清除它:
-
clear()、flip()、rewind()都会将mark设为-1 -
compact()保留未读数据并重设position,但也会清空mark - 写入操作(如
put())不会影响mark,但通常发生在写模式,与读场景分离 - 务必在调用
reset()前检查buffer.isReadOnly()或是否已标记,避免异常
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










