发现JDK源码中一块可以优化的代码

文章目录

  • 前言
  • 一、问题是什么?
  • 二、为什么这里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语句明显更容易理解,而且少了一次比较的过程,各位我理解的对吗?

原文链接:,转发请注明来源!