如果我有一个String
的设定数量,我想在自由格式字段中检查(计算机生成,也可能是每秒很多),这将是一个更快的实现?
private static HashSet<String> values = new HashSet<String>();
static {
... add 5 Strings to the Set
}
public void someMethod() {
if (values.contains(enteredValue))
...
}
或使用5 String.equals
||进行if?
这对我来说似乎不费吹灰之力,但也许我错了。一个而不是另一个的任何缺点?
答案 0 :(得分:5)
我相信HashSet
会更快,因为它会将您的字符串哈希一次,然后进行5次整数比较。这比进行5次String
比较要快得多。
话虽如此,我建议你只选择一种方法然后尝试一下。如果它的执行速度不够快,那就担心更多地优化它。
答案 1 :(得分:2)
字符串source code:
哈希相关代码:
/** Cache the hash code for the string */
private int hash; // Default to 0
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31 * h + val[off++];
}
hash = h;
}
return h;
}
等于代码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
因此,每个字符串都涉及字符串中所有字符的单个循环,哈希值只为每个字符串计算一次,但与哈希计算循环不同,等号循环在第一个字符不匹配时抢先退出,并且而且,如果字符串具有不同的长度,则甚至不会发生等于循环。
我的直觉是,除非你一遍又一遍地将相同的字符串与相同的字符串进行比较,否则等于获胜。
艰难的电话。如果您真的想知道哪个更适合您的应用程序,请做一个基准测试。
答案 2 :(得分:1)
只有一种方法可以确定 - 用现实值来衡量它。
答案 3 :(得分:1)
这取决于字符串的长度,内容和数量。
如果字符串很少且随机填充,那么简单比较很可能会在一个或两个字符内找到不匹配,只有当内容完全匹配时才进一步检查。与HashSet
维护和哈希码生成(每次都是完整字符串)的开销相比,我打赌简单比较。
如果字符串可能相似或更多,HashSet
会更好。
[请注意,假设HashSet
的答案会更快,忽略您必须为HashSet
的每次添加生成哈希码,而不仅仅是查找。但是,如果你的参考字符串不随时间改变,那么这个事实并不重要。]
答案 4 :(得分:0)
来自http://en.wikipedia.org/wiki/Java_hashCode%28%29#The_java.lang.String_hash_function
从Java 1.2开始,java.lang.String类 使用a实现其hashCode() 整个产品和算法 字符串的文字。
在这里疯狂猜测,但我不认为会有太大的区别,因为计算哈希本身与进行直接字符串比较的成本大致相同,而且你可能不得不处理冲突。
答案 5 :(得分:0)
HashSet
不一定会更快,但时间将常量。引用Java文档。
这门课提供恒定的时间 基本操作的性能 (添加,删除,包含和大小)
因此,如果您添加更多字符串以搜索该值,如果您使用等于时间将相对于字符串 n 的数字但是HashSet
它将保留恒定。
答案 6 :(得分:0)
如果您对字符串进行排序并进行二进制搜索,那么您最多将进行三次compareTo
次测试。如果使用HashSet,则必须计算测试字符串的哈希值,并至少进行一次equals
测试(如果匹配哈希码)或不进行equals
测试(针对未命中)。我不清楚这里是否会有很大的不同,实际的性能可能取决于次优问题,如优化水平。
答案就像对待这类问题一样,是基准。
答案 7 :(得分:0)
在发现 string.equals
速度更快后来到这里寻找答案 - 并且与我的预期相反。但这是代码和结果。请反馈...
这是以纳秒为单位的结果:
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.HashSet;
public class Main {
HashMap<Integer, String> testKeys = new HashMap<>();
HashSet<String> keys2 = new HashSet<>();
String key1 = null;
String key2 = null;
static HashMap<String, Long> results = new HashMap<String, Long>();
public static void main(String[] args) {
var test1 = new Main();
var test2 = new Main();
test1.init();
test2.init();
Instant start, finish;
long timeElapsed;
for (int i = 0; i < 10; i++) {
start = Instant.now();
test1.stringCompare();
finish = Instant.now();
timeElapsed = getElapsed(start, finish);
addResult("stringCompare", timeElapsed);
System.out.println("test1.run1 stringCompare time elapsed: " + timeElapsed);
start = Instant.now();
test2.stringCompare();
finish = Instant.now();
timeElapsed = getElapsed(start, finish);
addResult("stringCompare", timeElapsed);
System.out.println("test2.run1 stringCompare time elapsed: " + timeElapsed);
//
start = Instant.now();
test1.mapSetContains();
finish = Instant.now();
timeElapsed = getElapsed(start, finish);
addResult("mapSetContains", timeElapsed);
System.out.println("test2.run1 mapSetContains time elapsed: " + timeElapsed);
start = Instant.now();
test2.mapSetContains();
finish = Instant.now();
timeElapsed = getElapsed(start, finish);
addResult("mapSetContains", timeElapsed);
System.out.println("test2.run2 mapSetContains time elapsed: " + timeElapsed);
}
emitResults();
}
static void emitResults(){
for (String item : results.keySet()) {
System.out.println("item: " + item + " " + results.get(item));
}
}
static void addResult(String testType, Long result) {
if (results.containsKey(testType))
results.put(testType, results.get(testType) + result);
else
results.put(testType, result);
}
static long getElapsed(Instant start, Instant finish) {
long timeElapsed;
timeElapsed = Duration.between(start, finish).toNanos(); // .toMillis();
return timeElapsed;
}
void stringCompare() {
for (int i = 0; i < testKeys.size(); i++) {
String testKey = testKeys.get(i);
boolean rv = testKey.equals(key1) || testKey.equals(key2);
}
}
void mapSetContains() {
for (int i = 0; i < testKeys.size(); i++) {
String testKey = testKeys.get(i);
boolean rv = keys2.contains(testKey);
}
}
void init() {
for (int i = 0; i < 4; i++) {
testKeys.put(i, makeUiid());
}
key1 = testKeys.get(0);
key2 = testKeys.get(1);
keys2.add(testKeys.get(2));
keys2.add(testKeys.get(3));
}
String makeUiid() {
return java.util.UUID.randomUUID().toString();
}
}