【问题标题】:Correct way of converting String to Long in Java [duplicate]在Java中将String转换为Long的正确方法[重复]
【发布时间】:2017-02-07 23:30:52
【问题描述】:

在 Java 中将 String 转换为 Long(对象)的最佳方式是什么。

Long a = new Long(str);

Long a = Long.parseLong(str);

这里是否有正确的方法,因为两者似乎具有相同的可读性,并且在第一种方法中添加 autoboxing 的额外步骤是否可以接受?

【问题讨论】:

  • 我有点好奇,为什么有人想要缓存单个对象,因为问题还建议将单个字符串对象转换为 long
  • @PavneetSingh 这些事情可能会在一个循环或很长一段时间内发生,Long 实例可能会被放入数百万个实例的集合中。在这种情况下(当大多数值实际上可以从缓存中检索到时),缓存可以节省大量内存。
  • @qqilihq 第一个缓存不能存储数百万个实例,而且它的范围非常有限,基本上它是用于 java 内部实现而不是提高性能,有关更清晰的信息,请阅读下面的答案(不要知道为什么有人会否决它可能是故意这样做的):P:P
  • 虽然这是一个重复,但在这里投了赞成票;因为对于新手来说,这只是一个写得很好的问题;-)

标签: java autoboxing


【解决方案1】:

仔细查看返回类型:

  1. Long.parseLong(String) 返回一个 primitive long,因此在这种情况下会重新装箱:Long a = Long.parseLong(str);
  2. new Long(String) 在每种情况下都会创建一个 new Long 对象。所以,不要这样做,而是选择 3)
  3. Long.valueOf(String) 返回一个 Long 对象,并将返回某些值的缓存实例——因此,如果您需要 Long,这是首选变体。

检查java.lang.Long 源,缓存包含以下值(Sun JDK 1.8):

private static class LongCache {
    private LongCache(){}

    static final Long cache[] = new Long[-(-128) + 127 + 1];

    static {
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Long(i - 128);
    }
}

【讨论】:

  • 所以最好的方法是使用 Long.valueOf(str) :) 谢谢
  • @Humus 对我来说似乎不是,看看我的答案,可能会有所帮助
  • 我发布我的答案只是为了指导其他人,虽然可能是为了像你这样的其他优秀社区成员来纠正你的错误,而不是你试图证明官方文档是错误的,而你不能
  • @PavneetSingh 请具体说明我的“错误”以及我将在哪里证明任何错误。
  • 仔细阅读我的答案,将你的答案与我的答案进行比较,你会发现它自己
【解决方案2】:

最好的方法是Long.valueOf(str),因为它依赖于Long.valueOf(long),它使用内部缓存使其更高效,因为它会在需要时重用Long 的缓存实例,包括从-128127

返回一个代表指定 long 值的 Long 实例。如果一个 new Long 实例不是必须的,这个方法一般应该是 优先使用构造函数Long(long),因为这种方法是 可能会产生显着更好的空间和时间性能 缓存经常请求的值。请注意,与 Integer类中对应的方法,这个方法不是必须的 缓存特定范围内的值。

一般来说,使用 IntegerBooleanLong 等包装类的 static 工厂方法 valueOf(str) 是一个好习惯,因为它们中的大多数都会在任何时候重用实例有可能使它们在内存占用方面比相应的parse 方法或构造函数更有效。


摘自Joshua Bloch撰写的Effective JavaItem 1

您通常可以通过使用 static 来避免创建不必要的对象 工厂方法(第 1 项)优先于不可变的构造函数 提供两者的类。比如静态工厂方法 Boolean.valueOf(String) 几乎总是比 构造函数Boolean(String)。构造函数创建一个新对象 每次调用它,而静态工厂方法永远不会 必须这样做,但实际上不会这样做。

【讨论】:

    【解决方案3】:

    我想建议使用Long.parseLong 而不是其他所有选项,因为:

    • 所有其他函数,即Long.valueOfLong(string) 都依赖于Long.parseLong 方法,该方法作为每个StringLong 转换的核心方法。
    • 关于缓存,当您的输入仅在 -128 到 127 之间时,这将起作用(请参见下面的示例),因此由您想要直接或通过调用 Long.parseLong 的编码器决定Long.valueOf 当你的对象是 String 类型时。(显然,使用直接调用)。official docssource code link (为什么不使用 Byte 而不是 Long ,因为缓存甚至不会保存每个 long 值这个范围也适用于整数)

    来自官方文档

    public static Long valueOf(String s)
                        throws NumberFormatException
    Returns a Long object holding the value of the specified String. The argument is interpreted as representing a signed decimal long, exactly as if the argument were given to the parseLong(java.lang.String) method. The result is a Long object that represents the integer value specified by the string.
    **In other words, this method returns a Long object equal to the value of:**
    
    new Long(Long.parseLong(s))
    
    // internally calls to Long.valueOf when you pass string
    
    public static Long valueOf(String s) throws NumberFormatException
    {
        return Long.valueOf(parseLong(s, 10));
    }
    
    • 关于Long.valueOf 返回一个直接的 Wrapper 对象而不创建 new Long 对象是一个错误的陈述,因为根据内部使用 Long.parseLong(它返回一个original long) ,Long.parseLong 的原始输出将通过创建Long 类的新对象转换为Wrapper 对象,因此您想直接使用Boxing 或可以调用Long.valueOf=&gt;Long.parseLong=&gt;new Long

    关于缓存的更多信息(如果传递值很长):

    当您想使用 == 进行 Object 类型的相等性检查(如实习生字符串)时,缓存几乎没有帮助。长缓存只会保留值在 -128 to 127 范围(含)之间的静态对象数组,因此如果您的数字超出此范围,则您将无法使用 == 相等检查运算符(你不信,试试下面的例子)

    示例:

        Long b2=128L;
        Long b3=128L;
        Long aa=Long.valueOf("134");
        Long ab=Long.valueOf("134");
        System.out.println(b2==b3); // no cache for out of range values
        System.out.println(aa==ab);  // no cache for out of range values
        System.out.println(aa.equals(ab)); // must use equals for equality check
        System.out.println(b2.equals(b3));
        b2=44; // between -128 to 127 it will work
        b3=44;
        System.out.println(b2==b3);
    

    输出:

    false
    false
    true
    true
    true
    

    所以尝试使用equals 进行相等检查。

    为什么需要缓存:因为在 -128 到 127 之间的数字出于JLS (5.1.7) 的性能原因需要给出标识,所以缓存不是为了时间/空间效率在这种情况下。

    public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache , range is clearly seen 
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
    }
    

    结论:

    • 使用Long.parseLong
    • 在使用 Wrapper 类时必须使用 equals
    • 仅当您希望将 -128 到 127 之间的数字与 Wrapper 类一起使用时,Java 缓存机制才有效。

    【讨论】:

    • 缓存肯定会为valueOf 工作,即使您提供字符串并且满足缓存条件。
    • @qqilihq 你可以分析源代码,我根据具体事实写了这篇文章另外我添加了更多细节来证明我的观点。只是因为它证明你的答案是错误的并不意味着你必须盲目地投反对票
    • @qqilihq 先阅读结论,有一些自相矛盾的东西我忘了删除,但我的结论陈述了你在否决之前甚至没有阅读和考虑的真实事实
    • 仍有无效语句。 Long.valueOf("1") 不会创建新的 Long 实例,而是从缓存中返回一个值。引用文档:“通过缓存频繁请求的值,此方法可能会产生明显更好的 空间时间性能”。你想证明什么?
    • @qqilihq 这个文档属于Long.valueOf(long input) 所以你正在考虑输入值很长的情况Long.valueOf(long l) 而不是Long.valueOf(String l) 所以去仔细阅读文档,这也证明了我的一个您在回答中提到的很多错误。 doc links to confirm 现在你有理由取消你的反对票了。
    【解决方案4】:

    来自源代码:

    public Long(String s) throws NumberFormatException {
        this.value = parseLong(s, 10);
    }
    

    如果您不相信:

    【讨论】:

      【解决方案5】:

      来自 Javadoc:

      构造一个新分配的 Long 对象,表示 long String 参数指示的值。字符串被转换为 与 parseLong 方法使用的方式完全相同的 long 值 基数 10。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-03
        • 1970-01-01
        • 2021-10-08
        • 2019-07-31
        • 2012-05-01
        • 2021-10-24
        • 2014-07-23
        • 2018-10-24
        相关资源
        最近更新 更多