Đánh giá các câu trả lời chính với điểm chuẩn hiệu suất xác nhận mối lo ngại rằng câu trả lời được chọn hiện tại làm cho các hoạt động regex tốn kém dưới mui xe
Đến nay, các câu trả lời được cung cấp có 3 kiểu chính (bỏ qua câu trả lời JavaScript;)):
- Sử dụng String.replace (charsToDelete, ""); trong đó sử dụng regex dưới mui xe
- Sử dụng Lambda
- Sử dụng triển khai Java đơn giản
Về kích thước mã rõ ràng, String.replace là ngắn gọn nhất. Việc triển khai Java đơn giản nhỏ hơn và gọn gàng hơn (IMHO) so với Lambda (đừng hiểu sai ý tôi - Tôi thường sử dụng Lambdas khi chúng phù hợp)
Tốc độ thực thi là, theo thứ tự nhanh nhất đến chậm nhất: triển khai Java đơn giản, Lambda và sau đó là String.replace () (gọi ra regex).
Cho đến nay, việc triển khai nhanh nhất là việc triển khai Java đơn giản được điều chỉnh sao cho nó mở rộng bộ đệm StringBuilder với độ dài kết quả tối đa có thể và sau đó chỉ cần thêm các ký tự vào bộ đệm không nằm trong chuỗi "ký tự để xóa". Điều này tránh mọi phân bổ sẽ xảy ra đối với các chuỗi có độ dài> 16 ký tự (phân bổ mặc định cho StringBuilder) và nó tránh được hiệu năng "trượt sang trái" của việc xóa các ký tự khỏi bản sao của chuỗi xảy ra là triển khai Lambda.
Mã dưới đây chạy thử nghiệm điểm chuẩn đơn giản, chạy mỗi lần thực hiện 1.000.000 lần và ghi lại thời gian đã trôi qua.
Kết quả chính xác thay đổi theo từng lần chạy nhưng thứ tự hiệu suất không bao giờ thay đổi:
Start simple Java implementation
Time: 157 ms
Start Lambda implementation
Time: 253 ms
Start String.replace implementation
Time: 634 ms
Việc triển khai Lambda (như được sao chép từ câu trả lời của Kaplan) có thể chậm hơn vì nó thực hiện "dịch chuyển sang trái bởi một" của tất cả các ký tự ở bên phải của ký tự bị xóa. Điều này rõ ràng sẽ trở nên tồi tệ hơn đối với các chuỗi dài hơn với nhiều ký tự yêu cầu xóa. Ngoài ra, có thể có một số chi phí trong việc thực hiện Lambda.
Việc triển khai String.replace, sử dụng regex và thực hiện "biên dịch" regex tại mỗi cuộc gọi. Tối ưu hóa điều này sẽ là sử dụng regex trực tiếp và lưu trữ mẫu đã biên dịch để tránh chi phí biên dịch nó mỗi lần.
package com.sample;
import java.util.function.BiFunction;
import java.util.stream.IntStream;
public class Main {
static public String deleteCharsSimple(String fromString, String charsToDelete)
{
StringBuilder buf = new StringBuilder(fromString.length()); // Preallocate to max possible result length
for(int i = 0; i < fromString.length(); i++)
if (charsToDelete.indexOf(fromString.charAt(i)) < 0)
buf.append(fromString.charAt(i)); // char not in chars to delete so add it
return buf.toString();
}
static public String deleteCharsLambda(String fromString1, String charsToDelete)
{
BiFunction<String, String, String> deleteChars = (fromString, chars) -> {
StringBuilder buf = new StringBuilder(fromString);
IntStream.range(0, buf.length()).forEach(i -> {
while (i < buf.length() && chars.indexOf(buf.charAt(i)) >= 0)
buf.deleteCharAt(i);
});
return (buf.toString());
};
return deleteChars.apply(fromString1, charsToDelete);
}
static public String deleteCharsReplace(String fromString, String charsToDelete)
{
return fromString.replace(charsToDelete, "");
}
public static void main(String[] args)
{
String str = "XXXTextX XXto modifyX";
String charsToDelete = "X"; // Should only be one char as per OP's requirement
long start, end;
System.out.println("Start simple");
start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++)
deleteCharsSimple(str, charsToDelete);
end = System.currentTimeMillis();
System.out.println("Time: " + (end - start));
System.out.println("Start lambda");
start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++)
deleteCharsLambda(str, charsToDelete);
end = System.currentTimeMillis();
System.out.println("Time: " + (end - start));
System.out.println("Start replace");
start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++)
deleteCharsReplace(str, charsToDelete);
end = System.currentTimeMillis();
System.out.println("Time: " + (end - start));
}
}