Java 异常处理之 BufferUnderflowException(BufferUnderflowException 概述、常见发生场景、避免策略)

一、BufferUnderflowException 概述

  1. BufferUnderflowException 是 Java NIO 包中的一个运行时异常,是 RuntimeException 的子类
public class BufferUnderflowException extends RuntimeException {
    ...
}
# 继承关系

java.lang.Object
    -> java.lang.Throwable
        -> java.lang.Exception
            -> java.lang.RuntimeException
                -> java.nio.BufferUnderflowException
  1. 它发生在尝试从缓冲区读取比实际剩余更多的数据时,即缓冲区位置(position)已经到达或超过限制(limit)

二、常见发生场景

  1. 读取数据
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println("初始化");
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

int i1 = byteBuffer.getInt();// 读取 4 字节没问题
System.out.println("第 1 次读取:" + i1);
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

int i2 = byteBuffer.getInt();// 再读取 4 字节没问题
System.out.println("第 2 次读取:" + i2);
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

int i3 = byteBuffer.getInt(); // 再读取 4 字节,会抛出 BufferUnderflowException 异常
System.out.println("第 3 次读取:" + i3);
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());
# 输出结果

初始化
pos=0, remaining=10, limit=10
第 1 次读取:0
pos=4, remaining=6, limit=10
第 2 次读取:0
pos=8, remaining=2, limit=10
Exception in thread "main" java.nio.BufferUnderflowException
  1. 批量读取数据
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println("初始化");
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

byte[] bytes = new byte[15];
byteBuffer.get(bytes);
System.out.println("读取数据:" + new String(bytes));
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());
# 输出结果

初始化
pos=0, remaining=10, limit=10
Exception in thread "main" java.nio.BufferUnderflowException
  1. 调用 flip 方法后,(批量)读取数据
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println("初始化");
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

String data = "abc";
byteBuffer.put(data.getBytes());
System.out.println("添加数据:" + data);
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

byteBuffer.flip();
System.out.println("调用 flip 方法");
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

byte[] bytes1 = new byte[2];
byteBuffer.get(bytes1);
System.out.println("第 1 次读取:" + new String(bytes1));
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

byte[] bytes2 = new byte[2];
byteBuffer.get(bytes2);
System.out.println("第 2 次读取:" + new String(bytes2));
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());
# 输出结果

初始化
pos=0, remaining=10, limit=10
添加数据:abc
pos=3, remaining=7, limit=10
调用 flip 方法
pos=0, remaining=3, limit=3
第 1 次读取:ab
pos=2, remaining=1, limit=3
Exception in thread "main" java.nio.BufferUnderflowException

三、避免策略

1、基本介绍
  1. 总是调用 remaining 方法检查剩余数据是否足够,不同的读取方法对读取长度有不同的要求
方法读取长度(字节)
byte get()1
char getChar()2
short getShort()2
int getInt()4
long getLong()8
float getFloat()4
double getDouble()8
ByteBuffer get(byte[] dst)dst.length
  1. 必要时,也可以通过 try catch 捕获异常
2、演示
  1. 读取数据(调用 remaining 方法检查)
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println("初始化");
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

int num = 1;
while (true) {
    if (byteBuffer.remaining() >= 4) {
        int i1 = byteBuffer.getInt();
        System.out.println("第 " + num + " 次读取:" + i1);
        System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());
        num++;
    } else {
        System.out.println("第 " + num + " 次读取");
        System.out.println("数据不足,无法读取");
        break;
    }
}
# 输出结果

初始化
pos=0, remaining=10, limit=10
第 1 次读取:0
pos=4, remaining=6, limit=10
第 2 次读取:0
pos=8, remaining=2, limit=10
第 3 次读取
数据不足,无法读取
  1. 批量读取数据(调用 remaining 方法检查)
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println("初始化");
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

byte[] bytes = new byte[15];
if (byteBuffer.remaining() < bytes.length) {
    System.out.println("数据不足,无法读取");
} else {
    byteBuffer.get(bytes);
    System.out.println("读取数据:" + new String(bytes));
    System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());
}
# 输出结果

初始化
pos=0, remaining=10, limit=10
数据不足,无法读取
  1. 调用 flip 方法后,(批量)读取数据(调用 remaining 方法检查)
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println("初始化");
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

String data = "abc";
byteBuffer.put(data.getBytes());
System.out.println("添加数据:" + data);
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

byteBuffer.flip();
System.out.println("调用 flip 方法");
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

byte[] bytes1 = new byte[2];
if (byteBuffer.remaining() < bytes1.length) {
    System.out.println("第 1 次读取");
    System.out.println("数据不足,无法读取");
} else {
    byteBuffer.get(bytes1);
    System.out.println("第 1 次读取:" + new String(bytes1));
    System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());
}

byte[] bytes2 = new byte[2];
if (byteBuffer.remaining() < bytes2.length) {
    System.out.println("第 2 次读取");
    System.out.println("数据不足,无法读取");
} else {
    byteBuffer.get(bytes2);
    System.out.println("第 2 次读取:" + new String(bytes2));
    System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());
}
# 输出结果

初始化
pos=0, remaining=10, limit=10
添加数据:abc
pos=3, remaining=7, limit=10
调用 flip 方法
pos=0, remaining=3, limit=3
第 1 次读取:ab
pos=2, remaining=1, limit=3
第 2 次读取
数据不足,无法读取
  1. 通过 try catch 捕获异常
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println("初始化");
System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());

try {
    byte[] bytes = new byte[15];
    byteBuffer.get(bytes);
    System.out.println("读取数据:" + new String(bytes));
    System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());
} catch (BufferUnderflowException e) {
    e.printStackTrace();
    System.out.println("读取数据失败");
    System.out.println("pos=" + byteBuffer.position() + ", remaining=" + byteBuffer.remaining() + ", limit=" + byteBuffer.limit());
}
# 输出结果

初始化
pos=0, remaining=10, limit=10
java.nio.BufferUnderflowException
读取数据失败
pos=0, remaining=10, limit=10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值