文章目录
- 前言
- 一、问题是什么?
- 二、为什么这里while和if的效果一样?1.slen < blen < len : 1000 < 8192 < 100002. slen < len < blen : 1000 < 1024 < 81923. blen < slen < len : 8192 < 10000 < 100104. blen < len < slen :8192 < 10000 < 100105. len < blen < slen : 1000 < 8192 < 100006. len < slen < blen : 1000 < 2000 < 8192
- 总结
前言
最近阅读了下JDK17中的InputStream源码,在读到其中readNBytes(int len)方法时,有一段代码让我产生了一些疑惑。所以便分析了下代码。理解的不对的话,希望各位大佬予以答疑解惑。
一、问题是什么?
我认为如下代码中 while 循环可以直接使用 if 语句替代。while循环不仅多了一次判断过程,而且相对来说if语句更容易理解。
jdk中源码如下:
public byte[] readNBytes(int len) throws IOException {
if (len < 0) {
throw new IllegalArgumentException("len < 0");
}
List<byte[]> bufs = null;
byte[] result = null;
int total = 0;
int remaining = len;
int n;
do {
byte[] buf = new byte[Math.min(remaining, DEFAULT_BUFFER_SIZE)];
int nread = 0;
//=================就是这里while换成if效果应该是一样的=================
// read to EOF which may read more or less than buffer size
while ((n = read(buf, nread,
Math.min(buf.length - nread, remaining))) > 0) {
nread += n;
remaining -= n;
}
//=================就是这里while换成if效果应该是一样的=================
if (nread > 0) {
if (MAX_BUFFER_SIZE - total < nread) {
throw new OutOfMemoryError("Required array size too large");
}
if (nread < buf.length) {
buf = Arrays.copyOfRange(buf, 0, nread);
}
total += nread;
if (result == null) {
result = buf;
} else {
if (bufs == null) {
bufs = new ArrayList<>();
bufs.add(result);
}
bufs.add(buf);
}
}
// if the last call to read returned -1 or the number of bytes
// requested have been read then break
} while (n >= 0 && remaining > 0);
if (bufs == null) {
if (result == null) {
return new byte[0];
}
return result.length == total ?
result : Arrays.copyOf(result, total);
}
result = new byte[total];
int offset = 0;
remaining = total;
for (byte[] b : bufs) {
int count = Math.min(b.length, remaining);
System.arraycopy(b, 0, result, offset, count);
offset += count;
remaining -= count;
}
return result;
}
二、为什么这里while和if的效果一样?
这里我们首先给流的长度,缓冲区的长度,要读取的字节长度分别定义一个简短的名称,方便后面引用:
slen = stream.length //流的长度
blen = buf.lenghth = 8192 //缓冲区的大小
remaining = len //len是要读取的字节长度
接下来我们根据上述三个长度分别列出可能出现的六种情况:
1.slen < blen < len : 1000 < 8192 < 10000
第一遍循环想要读取blen(8192)个元素,实际读取slen(1000)个元素,
第二遍循环想要读取7192个元素,返回-1,未进入循环
2. slen < len < blen : 1000 < 1024 < 8192
第一遍循环想要读取len(1024)个元素,实际读取slen(1000)个元素,
第二遍循环想要读取24个元素,返回-1,未进入循环。
3. blen < slen < len : 8192 < 10000 < 10010
第一遍循环想要读取blen(8192)个元素,实际读取blen(8192)个元素,
第二遍循环想要读取0个元素,返回0,未进入循环。
4. blen < len < slen :8192 < 10000 < 10010
第一遍想要读取blen(8192)个元素,实际读取blen(8192)个元素,
第二遍循环想要读取0个元素,返回0,未进入循环。
5. len < blen < slen : 1000 < 8192 < 10000
第一遍想要读取len(1000)个元素,实际读取len(1000)个元素,
第二遍想要读取0个元素,返回0,未进入循环。
6. len < slen < blen : 1000 < 2000 < 8192
第一遍想要读取len(1000)个元素,实际读取len(1000)个元素,
第二遍想要读取0个元素,返回0,未进入循环。
总结
while ((n = read(buf, nread,
Math.min(buf.length - nread, remaining))) > 0) {
nread += n;
remaining -= n;
}
上述while循环的代码在这段代码中的效果相当于以下if语句的代码:
if((n = read(buf, nread,
Math.min(buf.length - nread, remaining))) > 0) {
nread += n;
remaining -= n;
}
但使用if语句明显更容易理解,而且少了一次比较的过程,各位我理解的对吗?