如何避免关于原始类型的代码重复?
How to avoid duplication of code regarding primitive types?
背景
位输入流由字节数组支持。有一些方法可以将该字节数组读取到各种强制原始数组中。
问题
有重复代码。 Java 缺少基本类型的泛型,所以重复可能是不可避免的。
代码
重复代码明显在以下方法中:
@Override
public long readBytes(final byte[] out, final int offset, final int count, final int bits) {
final int total = offset + count;
assert out != null;
assert total <= out.length;
final long startPosition = position();
for (int i = offset; i < total; i++) {
out[i] = readByte(bits);
}
return position() - startPosition;
}
@Override
public long readShorts(final short[] out, final int offset, final int count, final int bits) {
final int total = offset + count;
assert out != null;
assert total <= out.length;
final long startPosition = position();
for (int i = offset; i < total; i++) {
out[i] = readShort(bits);
}
return position() - startPosition;
}
请注意 final byte[] out
如何与 readByte(bits)
相关,就像 final short[] out
与 readShort(bits)
有关。这些关系才是问题的关键。
问题
如何消除重复,如果有的话,又不会对性能造成重大影响(例如,通过自动装箱)?
相关
如果您正在阅读您的代码似乎表明的批量原语,使用 ByteBuffer methods like asDoubleBuffer() or asShortBuffer() 将卸载一些最低级别的工作。
示例:
public void readBytes( final byte[] out, final int offset, final int count, final ByteBuffer buffer ) {
buffer.get( out, offset, count ); // udates ByteBuffer `position` automatically
}
public void readShorts( final short[] out, final int offset, final int count, final ByteBuffer buffer ) {
ShortBuffer sb = buffer.asShortBuffer();
sb.get( out, offset, count ); // note that `count` reads two bytes for each `short`
}
(代码编译但未测试!)
一种可能会导致性能下降的方法是使用 java.lang.reflect.Array
将数组视为对象,然后允许在所有读取方法中重复使用相同的代码。
@FunctionalInterface
public interface BitArrayReader {
Object read(int bits);
}
private long readPrimitive(
final Object out, final int offset, final int count, final int bits,
final BitArrayReader reader) {
final int total = offset + count;
assert out != null;
assert total <= Array.getLength(out);
final long startPosition = position();
for (int i = offset; i < total; i++) {
Array.set(out, i, reader.read(bits));
}
return position() - startPosition;
}
@Override
public long readBooleans(boolean[] out, int offset, int count, int bits) {
return readPrimitive(out, offset, count, bits, this::readBoolean);
}
以牺牲一些性能、轻微缺乏编译时类型安全和使用反射为代价解决了重复问题。
背景
位输入流由字节数组支持。有一些方法可以将该字节数组读取到各种强制原始数组中。
问题
有重复代码。 Java 缺少基本类型的泛型,所以重复可能是不可避免的。
代码
重复代码明显在以下方法中:
@Override
public long readBytes(final byte[] out, final int offset, final int count, final int bits) {
final int total = offset + count;
assert out != null;
assert total <= out.length;
final long startPosition = position();
for (int i = offset; i < total; i++) {
out[i] = readByte(bits);
}
return position() - startPosition;
}
@Override
public long readShorts(final short[] out, final int offset, final int count, final int bits) {
final int total = offset + count;
assert out != null;
assert total <= out.length;
final long startPosition = position();
for (int i = offset; i < total; i++) {
out[i] = readShort(bits);
}
return position() - startPosition;
}
请注意 final byte[] out
如何与 readByte(bits)
相关,就像 final short[] out
与 readShort(bits)
有关。这些关系才是问题的关键。
问题
如何消除重复,如果有的话,又不会对性能造成重大影响(例如,通过自动装箱)?
相关
如果您正在阅读您的代码似乎表明的批量原语,使用 ByteBuffer methods like asDoubleBuffer() or asShortBuffer() 将卸载一些最低级别的工作。
示例:
public void readBytes( final byte[] out, final int offset, final int count, final ByteBuffer buffer ) {
buffer.get( out, offset, count ); // udates ByteBuffer `position` automatically
}
public void readShorts( final short[] out, final int offset, final int count, final ByteBuffer buffer ) {
ShortBuffer sb = buffer.asShortBuffer();
sb.get( out, offset, count ); // note that `count` reads two bytes for each `short`
}
(代码编译但未测试!)
一种可能会导致性能下降的方法是使用 java.lang.reflect.Array
将数组视为对象,然后允许在所有读取方法中重复使用相同的代码。
@FunctionalInterface
public interface BitArrayReader {
Object read(int bits);
}
private long readPrimitive(
final Object out, final int offset, final int count, final int bits,
final BitArrayReader reader) {
final int total = offset + count;
assert out != null;
assert total <= Array.getLength(out);
final long startPosition = position();
for (int i = offset; i < total; i++) {
Array.set(out, i, reader.read(bits));
}
return position() - startPosition;
}
@Override
public long readBooleans(boolean[] out, int offset, int count, int bits) {
return readPrimitive(out, offset, count, bits, this::readBoolean);
}
以牺牲一些性能、轻微缺乏编译时类型安全和使用反射为代价解决了重复问题。