【问题标题】:When to use CharSequence in an API何时在 API 中使用 CharSequence
【发布时间】:2012-10-25 10:26:26
【问题描述】:

我正在为一个包设计一个公共接口 (API)。我想知道,我应该通常使用CharSequence 而不是String。 (我主要说的是公共接口)。

这样做有什么缺点吗?这被认为是一种好的做法吗?

如果将它用于类似标识符的目的(当值与基于哈希的容器中的集合匹配时)呢?

【问题讨论】:

标签: java charsequence


【解决方案1】:

这确实取决于您的需求,不过我想说明String 的两个优点。

来自CharSequence's documentation

每个对象可能由不同的类实现,并且没有 保证每个类都能够测试其实例 与对方的平等。因此不宜使用 任意 CharSequence 实例作为集合中的元素或作为键 地图。

因此,当您需要Map 或可靠的equals/hashCode 时,您需要将实例复制到String(或其他)中。

此外,我认为CharSequence 没有明确提到实现必须是不可变的。您可能需要进行防御性复制,这可能会减慢您的实施速度。

【讨论】:

  • 给定的链接显示页面未找到!
  • @VisruthCV 更新了链接,现在它指向 Java 7 版本。
【解决方案2】:

您可以实现CharSequence 来保存您的密码,因为usage of String is discouraged 用于此目的。实现应该有一个 dispose 方法来清除纯文本数据。

【讨论】:

    【解决方案3】:

    CharSequence 在通用库中很少使用。当您的主要用例是字符串处理(操作、解析等)时,通常应该使用它。

    一般来说你可以用CharSequence做任何你可以用String做的事情(很简单,因为你可以convert every CharSequence into a String)。但是有一个重要的区别:CharSequence 不能保证是不可变的! 每当您处理 String 并在两个不同的时间点检查它时,您可以确定它具有每次都相同的值。

    但对于CharSequence,这不一定是真的。例如,有人可以将 StringBuilder 传递到您的方法中并在您使用它时修改它,这可能会破坏很多正常的代码。

    考虑这个伪代码:

    public Object frobnicate(CharSequence something) {
      Object o = getFromCache(something);
      if (o == null) {
        o = computeValue(something);
        putIntoCache(o, something);
      }
      return o;
    }
    

    这看起来很无害,如果你在这里使用了String,它大部分都可以工作(除了这个值可能会被计算两次)。但是如果somethingCharSequence,那么它的内容可能会在getFromCache 调用和computeValue 调用之间发生变化。或者更糟:在computeValue 调用和putIntoCache 调用之间!

    因此:只有接受CharSequence,如果有很大的优势并且你知道缺点

    如果你接受CharSequence,你应该记录你的API如何处理可变的CharSequence对象。例如:“在方法执行时修改参数会导致未定义的行为。”

    【讨论】:

    • 例如,某人可以将 StringBuilder 传递到您的方法中,并在您使用它时对其进行修改 这不能用于许多类,尤其是 List?我的图书馆代码是否应该只接受ImmutableList?是的,有人可以在您的方法处理列表时更改列表,但他们会很愚蠢。如果它冒着你的不变量的风险,那么在验证输入之前做一个防御性的副本。
    • @MarkPeters:是的,这通常是正确的。这里的 区别在于,对于String,它永远不会改变的假设被硬编码到每个Java 开发人员的大脑中(而大多数人假设List 是可变的)。因此,当从String 切换到CharSequence 时,他们可能会错过这样一个事实,即CharSequence 不一定与String 共享这个好属性。
    • 我想说 CharSequence over String 的另一个主要用例是“大”字符序列,因为 CharSequence impl 可能正在处理并非同时在内存中的数据。
    • @jtahlborn:没错,但我认为这是“字符串操作”的一个子集。
    • @jtahlborn:更准确地说,我的意思是“字符串处理”,例如,如果您输出或附加到某个日志文件,那么接受 CharSequence 可能会有用(以便能够记录StringBuilder,例如)。解析器是应该接受CharSequence 的另一个例子:它不需要内存中的所有内容,它只需要能够遍历每个字符。
    【解决方案4】:

    如果参数在概念上是一个字符序列,请使用 CharSequence。

    从技术上讲,字符串是一系列字符,但大多数情况下我们不会这样想;字符串更具原子性/整体性,我们通常不关心单个字符。

    想想 int - 虽然 int 在技术上是一个位序列,但我们通常不关心单个位。我们将整数作为原子事物进行操作。

    因此,如果您要对参数执行的主要工作是遍历其字符,请使用 CharSequence。如果要将参数作为原子操作,请使用 String。

    【讨论】:

      【解决方案5】:

      Java CharSequence 是一个接口。正如 API 所说,CharSequence 已在 CharBufferSegmentStringStringBufferStringBuilder 类中实现。因此,如果您想从所有这些类访问或接受您的 API,那么CharSequence 是您的选择。如果不是,那么String 非常适合公共 API,因为它非常简单并且每个人都知道它。记住CharSequence只给你4个方法,所以如果你通过一个方法接受CharSequence对象,那么你的输入操作能力就会受到限制。

      【讨论】:

      • 我不同意你的结束语。 CharSequence 上的方法之一是toString(),因此任何可以用 String 完成的事情也可以用任意 CharSequence 完成(只需调用 toString() 并使用您想到的任何操作能力)。
      • @AndrzejDoyle: toString() 对于特定的实现来说可能真的很昂贵。大多数实现需要将整个字符序列复制到一个新数组中。如果您的第一步是从CharSequence 获取String,那么您就是在以隐藏性能损失为代价来提供灵活性。这没有多大价值,还不如拿String让用户进行转换,这样他们就很清楚惩罚了。
      • @AndrzejDoyle:Mark Peters 已经为我回答了问题,我想添加一件事。您建议使用CharSequence.toString() 方法来进一步操作输入,那么您为什么不直接接受您的输入作为String。那么您不必将您的CharSequence 转换为String
      • "因此,如果您想从所有这些类访问或接受您的 API,那么 CharSequence 是您的选择。"我认为那句话是倒退的;您的 API 应该接受 CharSequence,而不是相反。 “...那么 String 对于公共 API 来说非常好,因为它非常简单”。真的吗?我认为可以从 String API 中学到很多东西(如果只是因为正则表达式)。最后说明:CharSequence 中只有两种方法可能String 更有优势:subSequencecharAt
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-09
      • 2011-08-17
      相关资源
      最近更新 更多