【问题标题】:Implement CharSequence in order to use String.join?实现 CharSequence 以使用 String.join?
【发布时间】:2016-05-15 15:09:29
【问题描述】:

我有一个全部覆盖toString() 的对象集合。 我想将它们写到控制台或连接到一个字符串,基本上是为集合创建一个toString()

我可以使用 for 循环来实现这一点。 String.join() 似乎是一个更好的方法,因为它消除了显式循环:

import java.util.ArrayList;

public class Foo
{
    private double member;

    public Foo()
    {
        member = Math.random();
    }

    @Override
    public String toString()
    {
        return "I'm foo " + member;
    }

    public static void main(String[] args)
    {
        ArrayList<Foo> foos = new ArrayList<>();
        foos.add(new Foo());
        foos.add(new Foo());
        foos.add(new Foo());
        foos.add(new Foo());
        foos.add(new Foo());
        foos.add(new Foo());

        // print collection with loop
        for (Foo foo : foos)
        {
            System.out.println(foo);
        }

        // print collection with String.join
        System.out.println(String.join(System.lineSeparator(), foos));  // fails
    }
}

为了使System.out.println() 工作,调用toString() 方法。无需显式实现接口。这似乎很容易,而且是一种常见的做法。

然而,要让String.join(CharSequence delimiter, Iterable&lt;? extends CharSequence&gt; elements) 工作,仅仅拥有toString() 方法是不够的。我需要一个Iterable&lt;? extends CharSequence&gt;,这意味着Foo 应该实现CharSequence

现在我通过委托给toString() 快速实现了该接口:

import java.util.ArrayList;
import java.util.stream.IntStream;

import java.lang.CharSequence;

public class Foo implements CharSequence
{
    private double member;

    public Foo()
    {
        member = Math.random();
    }

    @Override
    public char charAt(int index)
    {
        return toString().charAt(index);
    }

    @Override
    public IntStream chars()
    {
        return toString().chars();
    }

    @Override
    public IntStream codePoints()
    {
        return toString().codePoints();
    }

    @Override
    public int length()
    {
        return toString().length();
    }

    @Override
    public CharSequence subSequence(int start, int end)
    {
        return toString().subSequence(start, end);
    }

    @Override
    public String toString()
    {
        return "I'm foo " + member;
    }

    public static void main(String[] args)
    {
        ArrayList<Foo> foos = new ArrayList<>();
        foos.add(new Foo());
        foos.add(new Foo());
        foos.add(new Foo());
        foos.add(new Foo());
        foos.add(new Foo());
        foos.add(new Foo());

        System.out.println(String.join(System.lineSeparator(), foos));  
    }
}

但这似乎是相当多的代码,除了保证将对象转换为String 的可能性,每个Object 都以toString() 的形式存在之外,这似乎是相当多的代码。

解决方案中引入的样板代码大于它删除的样板代码。

我怎样才能让 String.join() 的课堂更有趣?

我应该走那条路并实现接口,还是应该即时运行一些转换?

【问题讨论】:

  • 你不需要实现default方法,所以chars()codePoints()已经过时了。但无论如何,为此目的实现CharSequence 仍然没有用,所以请坚持接受的答案。

标签: java string collections tostring charsequence


【解决方案1】:

根据使用情况,该路由可能效率低下,因为每次调用 CharSequence 方法都会重新调用 toString。例如,如果一个方法试图迭代每个字符,你会看到糟糕的性能。既然您使用的是 Java 8,为什么不使用 Streams API?

System.out.println(foos.stream()
        .map(Object::toString)
        .collect(Collectors.joining(System.lineSeparator())));

【讨论】:

  • 同样,这是一个快速实现,可以在性能方面进行改进。问题是关于实现接口所需的样板代码。
  • 嗯,是的,您确实需要实现接口的所有成员。但是,如果您需要为多个类执行此操作,则在 Java 8 中,您可以使用专门设计的接口来充当具有默认方法的 C++ 混合。
  • @Javier Martín:嗯,你只需要实现abstract 成员,所以问题的例子做的工作比必要的多。尽管如此,你关于糟糕表现的危险的说法仍然成立。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-17
  • 1970-01-01
  • 1970-01-01
  • 2013-06-30
  • 2012-10-25
  • 1970-01-01
  • 2017-04-21
相关资源
最近更新 更多