OptionalInt.isPresent字段的用途是什么?

时间:2018-09-10 00:57:36

标签: java

看看java.util.OptionalInt的源代码,一个可选的int由int valueboolean isPresent组成。获取空的可选int的唯一方法是通过OptionalInt.empty()方法,该方法返回OptionalInt.EMPTY,这是所有空的可选int的公共实例。

如果是这种情况,那么为什么将isPresent()方法实现为return isPresent而不是this == EMPTY并通过摆脱isPresent字段来减少内存使用? / p>

2 个答案:

答案 0 :(得分:4)

这是实现的选择,唯一能给出明确答案的人就是编写实现的人。

但是很可能是这样一种选择,它使代码的可读性,清晰度和可维护性超过了内存微优化。

担心布尔值在包装int的对象中占用的空间确实没有多大意义。如果该空间是相关的,则考虑对象标头至少需要8个字节(在32位JVM上,至少在64位上),因此不应首先使用OptionalInt(或Java)。已经。

Java并非用于编写受内存限制的应用程序,而是用于编写易于维护的代码。将isPresent()用作isPresent的吸气剂,更易于阅读,重构时出错更少,并且符合既定的Java编码惯例。

附带说明:由于Java对象是8字节对齐的,因此在删除isPresent时,它甚至可能不会使类变小。 正如Eugene在评论中指出的那样,实际上确实增加了大小,因为字段isPresent恰好位于边界上,然后又添加了7个字节用于填充。

答案 1 :(得分:3)

OptionalInt.empty()方法的文档中所述:

  

尽管这样做可能很诱人,但请避免测试对象是否为空   通过与==返回的实例与OptionalInt.empty()进行比较。   不能保证它是一个单例。而是使用#isPresent()

事实上,以下测试已通过:

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;

import java.lang.reflect.InvocationTargetException;
import java.util.OptionalInt;
import org.junit.jupiter.api.Test;

class Tests {
    @Test
    void test() {
        var empty = OptionalInt.empty();
        assertSame(empty, empty);
        var anotherEmpty = fabricateEmpty();
        assertFalse(anotherEmpty.isPresent());
        assertNotSame(empty, anotherEmpty);
    }

    private OptionalInt fabricateEmpty() {
        try {
            var constructor = OptionalInt.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            return constructor.newInstance();
        } catch (InstantiationException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
}

尽管看起来有些人为,但许多流行的框架还是使用反射或Unsafe来构造实例。