String .contains VS Set <string> .contains VS Regex String.matches()

时间:2016-08-09 10:31:35

标签: java string set

我在两个文件中有两组字符串不是很长(200~500字),如下所示:

File1          File2

this           window
that           good
word           work
java           fine
book           home

所有独特的单词。

现在首先从文件中读取字符串(逐行)并将它们存储在:

  1. Set<String> set1 Set<String> set2:可能如下所示:[this, that, word, java, book] [window, good, work, fine, home]
    1. String str1 String str2:可能如下所示:str1: thisthatwordjava str2: windowgoodworkfinehome 可以是str1: this,that,word,java(已分隔)用逗号表示。
    2. 现在有三种方法可以检查homeSet将出现的单词String

      1. 使用set1/2.contains("home")
      2. 使用str1/2.contains("home")
      3. 使用str1/2.matches("home")
      4. 以上所有内容都可以正常使用,但 BEST 中的哪一个

        注意:此问题的目的是因为检查字符串的频率非常高。

4 个答案:

答案 0 :(得分:2)

不要做出绩效假设

是什么让你认为String.contains会有更好的表现&#34;?

除了非常简单的情况之外,它不会是:

  • 您的字符串列表很短,
  • 要比较的字符串很短,
  • 你想进行一次性查询。

对于所有其他情况,Set方法将扩展并更好地工作。当然,您将拥有Set的内存开销而不是单个字符串,但即使您想存储数百万个字符串并比较长字符串,O(1)查找也将保持不变。

正确工作的正确数据结构和算法

使用更安全,更健壮的设计,尤其是在这里,它并不是一个难以实施的解决方案。正如你提到的那样,你会经常检查,然后一套方法对你来说肯定更好。

此外,String.contain将是不安全的,就好像你们两个都有匹配的字符串和子字符串,你的查找将失败。正如kennytm在评论中所说,如果我们使用你的例子,你就得到了&#34; java&#34;列表中的字符串,查找&#34; ava&#34;会匹配它,你显然不想要它。

选择正确的组合

您可能不想使用简单的HashSet或调整其设置。例如,你可以考虑一个Guava ImmutableSet,如果你的集合只创建一次但经常检查。

实施例

这就是我要做的事情,假设你想要一个不可变的集合(就像你说你从文件中读取字符串列表一样)。这是副手,没有验证,所以原谅缺乏仪式。

使用Java 8 + Guava

import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
import com.google.common.base.Splitter;

final Set<String> lookupTable = ImmutableSet.copyOf(
  Splitter.on(',')
    .trimResults()
    .omitEmptyStrings()
    .split(Files.asCharSource(new File("YOUR_FILE_PATH"), Charsets.UTF_8).read())
);

如果您想要允许空格和空字符串,请使用正确的路径,正确的字符集以及修剪或不修剪的季节。

仅使用Java 8

如果你不想使用Guava而只想使用vanilla Java,那么只需在Java 8中做这样的事情(再次,道歉,未经测试):

final Set<String> lookupTable =
    Files.lines(Paths.get("YOUR_FILE_PATH"))
      .map(line -> line.split(",+"))
      .map(Arrays::stream)
      .collect(toSet());

使用Java&lt; 8

如果你有Java&lt; 8,然后使用通常的FileInputStream读取文件,然后使用String.split []或StringTokenizer提取数组,最后将数组条目添加到Set中。

答案 1 :(得分:0)

我猜你无论如何都要把文件的行读成一个字符串,所以如果你只计划一个查询,那么拆分它并将子字符串存储在一个集合中并不是最理想的。

答案 2 :(得分:0)

如果您想了解一些有关性能差异的信息。只需测量它。这是一个适合您的测试设置。

final int WORDS = 10000;
final int SEARCHES = 1000000;

Set<String> strSet = new TreeSet<String>();
String strStr = "";
int[] searches = new int[SEARCHES];
Random randomGenerator = new Random();

// filling set and string
for(int i = 0; i < WORDS; i++){
    strSet.add(String.valueOf(i));
    strStr += "," + String.valueOf(i);
}

// creating searches
for(int i = 0; i < SEARCHES; i++)
    searches[i] = randomGenerator.nextInt(WORDS);

// measure set
long startTime = System.currentTimeMillis();
for(int i = 0; i < SEARCHES; i++)
    strSet.contains(String.valueOf(searches[i]));
System.out.println("set result " + (System.currentTimeMillis() - startTime));

// measure string
startTime = System.currentTimeMillis();
for(int i = 0; i < SEARCHES; i++)
    strStr.contains(String.valueOf(searches[i]));
System.out.println("string result " + (System.currentTimeMillis() - startTime));

对我来说,输出是一个有意义的证明,你应该留在Set

  

设定结果350
  字符串结果14197

答案 3 :(得分:0)

如果给出没有逗号的单词,可以占用更多的内存空间,但执行时间更短(可以通过简单的拆分完成)

但我真正认为最好的方法是实验证明System.currentTimeMillis()