Có cách nào để kiểm tra xem có tồn tại enum hay không bằng cách so sánh nó với một chuỗi đã cho? Tôi dường như không thể tìm thấy bất kỳ chức năng nào như vậy. Tôi chỉ có thể thử sử dụng phương pháp valueOf
và bắt một ngoại lệ nhưng tôi đã được dạy rằng bắt ngoại lệ thời gian chạy không phải là thực hành tốt. Có ai có ý kiến gì không?Kiểm tra xem có tồn tại enum trong Java
Trả lời
Tôi không nghĩ rằng có một cách tích hợp để làm điều đó mà không bị bắt ngoại lệ. Bạn có thể sử dụng thay vì một cái gì đó như thế này:
public static MyEnum asMyEnum(String str) {
for (MyEnum me : MyEnum.values()) {
if (me.name().equalsIgnoreCase(str))
return me;
}
return null;
}
Edit: Như ghi chú Jon Skeet, values()
công trình bằng cách nhân bản một mảng ủng hộ tin mỗi khi nó được gọi. Nếu hiệu suất là quan trọng, bạn có thể muốn gọi values()
chỉ một lần, bộ nhớ cache mảng, và lặp qua đó.
Ngoài ra, nếu enum của bạn có một số lượng lớn các giá trị, thay thế bản đồ của Jon Skeet có khả năng hoạt động tốt hơn bất kỳ lần lặp mảng nào.
Tôi không biết tại sao ai đó nói với bạn rằng bắt ngoại lệ thời gian chạy là xấu.
Sử dụng valueOf
và bắt IllegalArgumentException
là tốt để chuyển đổi/kiểm tra chuỗi thành enum.
Không, IMO. Đó là thử nghiệm một tình huống không đặc biệt thông qua các ngoại lệ - sử dụng chúng để kiểm soát luồng trong điều kiện bình thường, không phải lỗi. Đó là việc sử dụng rất ít ngoại lệ IMO và một trong số đó có thể có tác động hiệu suất đáng kể. Ngoại lệ là tốt về hiệu suất bình thường, bởi vì chúng không nên xảy ra - nhưng khi bạn sử dụng chúng cho các điều kiện không phải lỗi, sau đó mã * trông * giống như nó sẽ chạy nhanh có thể bị sa lầy. –
Điều thú vị - dựa trên ý kiến này (mà tôi thường chia sẻ), tôi đã quyết định sử dụng phương thức "EnumUtils.isValidEnum' của Apache Commons để làm cho nó" sạch ". Và đoán làm thế nào 'EnumUtils.isValidEnum' được thực hiện - bắt' IllegalArgumentException' tất nhiên :-) –
Giải pháp làm việc ngắn nhất. –
Nếu tôi cần làm điều này, đôi khi tôi xây dựng một tên là Set<String>
hoặc thậm chí là của riêng mình Map<String,MyEnum>
- thì bạn chỉ có thể kiểm tra điều đó.
Một vài điểm đáng chú ý:
- dụng nhất bất kỳ bộ sưu tập tĩnh như vậy trong một initializer tĩnh. Không sử dụng trình khởi tạo biến và sau đó dựa vào nó đã được thực thi khi hàm tạo enum chạy - nó sẽ không được! (Các hàm khởi tạo enum là những thứ đầu tiên được thực hiện trước bộ khởi tạo tĩnh.)
- Cố gắng tránh sử dụng
values()
thường xuyên - nó phải tạo và điền một mảng mới mỗi lần. Để lặp qua tất cả các phần tử, hãy sử dụngEnumSet.allOf
hiệu quả hơn cho các enums mà không có nhiều yếu tố.
Mẫu mã:
import java.util.*;
enum SampleEnum {
Foo,
Bar;
private static final Map<String, SampleEnum> nameToValueMap =
new HashMap<String, SampleEnum>();
static {
for (SampleEnum value : EnumSet.allOf(SampleEnum.class)) {
nameToValueMap.put(value.name(), value);
}
}
public static SampleEnum forName(String name) {
return nameToValueMap.get(name);
}
}
public class Test {
public static void main(String [] args)
throws Exception { // Just for simplicity!
System.out.println(SampleEnum.forName("Foo"));
System.out.println(SampleEnum.forName("Bar"));
System.out.println(SampleEnum.forName("Baz"));
}
}
Tất nhiên, nếu bạn chỉ có một vài tên này có lẽ là quá mức cần thiết - một O (n), giải pháp thường thắng trên một O (1) giải pháp khi n là nhỏ đủ. Dưới đây là cách tiếp cận khác:
import java.util.*;
enum SampleEnum {
Foo,
Bar;
// We know we'll never mutate this, so we can keep
// a local copy.
private static final SampleEnum[] copyOfValues = values();
public static SampleEnum forName(String name) {
for (SampleEnum value : copyOfValues) {
if (value.name().equals(name)) {
return value;
}
}
return null;
}
}
public class Test {
public static void main(String [] args)
throws Exception { // Just for simplicity!
System.out.println(SampleEnum.forName("Foo"));
System.out.println(SampleEnum.forName("Bar"));
System.out.println(SampleEnum.forName("Baz"));
}
}
'values ()' tạo và điền một mảng mới? Tôi không nhớ điều đó trước đây, nhưng có lẽ bạn có một nguồn? –
Vâng nó trả về một mảng ... và nó không thể bảo vệ bạn khỏi việc đột biến mảng đó ... và nó sẽ không tiếp theo người gọi bị cản trở bởi điều đó. Ngoài ra, hãy nhìn vào các nguồn JRE :) –
Nó không có trong các nguồn JRE, đó là lý do tại sao tôi hỏi. Nhưng tôi đã không nghĩ đến khía cạnh đột biến; có lẽ bạn đã đúng rồi. –
Dựa trên Jon Skeet câu trả lời tôi đã thực hiện một lớp cho phép làm điều đó một cách dễ dàng tại nơi làm việc:
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* <p>
* This permits to easily implement a failsafe implementation of the enums's valueOf
* Better use it inside the enum so that only one of this object instance exist for each enum...
* (a cache could solve this if needed)
* </p>
*
* <p>
* Basic usage exemple on an enum class called MyEnum:
*
* private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
* public static MyEnum failSafeValueOf(String enumName) {
* return FAIL_SAFE.valueOf(enumName);
* }
*
* </p>
*
* <p>
* You can also use it outside of the enum this way:
* FailSafeValueOf.create(MyEnum.class).valueOf("EnumName");
* </p>
*
* @author Sebastien Lorber <i>([email protected])</i>
*/
public class FailSafeValueOf<T extends Enum<T>> {
private final Map<String,T> nameToEnumMap;
private FailSafeValueOf(Class<T> enumClass) {
Map<String,T> map = Maps.newHashMap();
for (T value : EnumSet.allOf(enumClass)) {
map.put(value.name() , value);
}
nameToEnumMap = ImmutableMap.copyOf(map);
}
/**
* Returns the value of the given enum element
* If the
* @param enumName
* @return
*/
public T valueOf(String enumName) {
return nameToEnumMap.get(enumName);
}
public static <U extends Enum<U>> FailSafeValueOf<U> create(Class<U> enumClass) {
return new FailSafeValueOf<U>(enumClass);
}
}
Và kiểm tra đơn vị:
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
* @author Sebastien Lorber <i>([email protected])</i>
*/
public class FailSafeValueOfTest {
private enum MyEnum {
TOTO,
TATA,
;
private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
public static MyEnum failSafeValueOf(String enumName) {
return FAIL_SAFE.valueOf(enumName);
}
}
@Test
public void testInEnum() {
assertNotNull(MyEnum.failSafeValueOf("TOTO"));
assertNotNull(MyEnum.failSafeValueOf("TATA"));
assertNull(MyEnum.failSafeValueOf("TITI"));
}
@Test
public void testInApp() {
assertNotNull(FailSafeValueOf.create(MyEnum.class).valueOf("TOTO"));
assertNotNull(FailSafeValueOf.create(MyEnum.class).valueOf("TATA"));
assertNull(FailSafeValueOf.create(MyEnum.class).valueOf("TITI"));
}
}
Lưu ý rằng tôi đã sử dụng ổi để tạo một bản đồ không thể thay đổi nhưng thực tế bạn có thể sử dụng một bản đồ bình thường mà tôi nghĩ vì bản đồ không bao giờ được trả lại ...
Một trong những lib yêu thích của tôi: Apache Commons.
EnumUtils có thể làm điều đó dễ dàng.
Dưới đây là một số mẫu mã để xác nhận một Enum:
MyEnum strTypeEnum = null;
// test if String str is compatible with the enum
if(EnumUtils.isValidEnum(MyEnum.class, str)){
strTypeEnum = MyEnum.valueOf(str);
}
Giải pháp tối thiểu tuyệt vời. – mumair
Cảm ơn nhận xét của bạn. Thực tế nó là tối thiểu vì sử dụng libs khác, thường là giải pháp tốt nhất so với việc tự mã hóa lại. bạn đang đi đến cùng một giải pháp tương tự ("Tái phát minh bánh xe") hoặc bạn bỏ lỡ một cái gì đó quan trọng và nó hoạt động tồi tệ nhất (sau đó trong trường hợp đó bạn "Tái phát minh bánh xe vuông") –
Có chính xác. bạn nhận được lợi ích đầy đủ hoặc tối đa từ nó :) Bánh xe vuông: P – mumair
Bạn cũng có thể sử dụng ổi và làm điều gì đó như thế này:
// This method returns enum for a given string if it exists, otherwise it returns default enum.
private MyEnum getMyEnum(String enumName) {
// It is better to return default instance of enum instead of null
return hasMyEnum(enumName) ? MyEnum.valueOf(enumName) : MyEnum.DEFAULT;
}
// This method checks that enum for a given string exists.
private boolean hasMyEnum(String enumName) {
return Iterables.any(Arrays.asList(MyEnum.values()), new Predicate<MyEnum>() {
public boolean apply(MyEnum myEnum) {
return myEnum.name().equals(enumName);
}
});
}
Trong phương pháp thứ hai tôi sử dụng ổi (Google Guava) thư viện mà cung cấp lớp học Iterables rất hữu ích. Sử dụng phương thức Iterables.any() chúng ta có thể kiểm tra xem một giá trị đã cho có tồn tại trong một đối tượng danh sách hay không. Phương thức này cần hai tham số: một danh sách và Cung cấp đối tượng. Đầu tiên tôi sử dụng phương thức Arrays.asList() để tạo danh sách với tất cả các enums. Sau đó, tôi đã tạo đối tượng Predicate được sử dụng để kiểm tra xem phần tử đã cho (có trong trường hợp của chúng tôi) thỏa mãn điều kiện trong áp dụng phương thức hay không. Nếu điều đó xảy ra, phương pháp Iterables.any() trả về giá trị thực.
Hầu hết các câu trả lời đều đề xuất sử dụng vòng lặp bằng để kiểm tra xem enum có tồn tại hay sử dụng try/catch với enum.valueOf() hay không. Tôi muốn biết phương pháp nào nhanh hơn và thử nó. Tôi không giỏi điểm chuẩn, vì vậy hãy sửa tôi nếu tôi phạm sai lầm.
Heres mã của lớp học chính của tôi:
package enumtest;
public class TestMain {
static long timeCatch, timeIterate;
static String checkFor;
static int corrects;
public static void main(String[] args) {
timeCatch = 0;
timeIterate = 0;
TestingEnum[] enumVals = TestingEnum.values();
String[] testingStrings = new String[enumVals.length * 5];
for (int j = 0; j < 10000; j++) {
for (int i = 0; i < testingStrings.length; i++) {
if (i % 5 == 0) {
testingStrings[i] = enumVals[i/5].toString();
} else {
testingStrings[i] = "DOES_NOT_EXIST" + i;
}
}
for (String s : testingStrings) {
checkFor = s;
if (tryCatch()) {
++corrects;
}
if (iterate()) {
++corrects;
}
}
}
System.out.println(timeCatch/1000 + "us for try catch");
System.out.println(timeIterate/1000 + "us for iterate");
System.out.println(corrects);
}
static boolean tryCatch() {
long timeStart, timeEnd;
timeStart = System.nanoTime();
try {
TestingEnum.valueOf(checkFor);
return true;
} catch (IllegalArgumentException e) {
return false;
} finally {
timeEnd = System.nanoTime();
timeCatch += timeEnd - timeStart;
}
}
static boolean iterate() {
long timeStart, timeEnd;
timeStart = System.nanoTime();
TestingEnum[] values = TestingEnum.values();
for (TestingEnum v : values) {
if (v.toString().equals(checkFor)) {
timeEnd = System.nanoTime();
timeIterate += timeEnd - timeStart;
return true;
}
}
timeEnd = System.nanoTime();
timeIterate += timeEnd - timeStart;
return false;
}
}
Điều này có nghĩa, mỗi phương pháp chạy 50000 lần so với chiều dài của enum Tôi chạy thử nghiệm này nhiều lần, với 10, 20, 50 và 100 hằng enum . Đây là kết quả:
- 10: try/catch: 760ms | lặp lại: 62ms
- 20: try/catch: 1671ms | iteration: 177ms
- 50: try/catch: 3113ms | lặp lại: 488ms
- 100: try/catch: 6834ms | lặp lại: 1760ms
Kết quả này không chính xác. Khi thực hiện nó một lần nữa, có sự khác biệt lên đến 10% trong kết quả, nhưng chúng đủ để cho thấy rằng phương pháp try/catch kém hiệu quả hơn nhiều, đặc biệt là với các enums nhỏ.
- 1. Kiểm tra xem bảng có tồn tại
- 2. Kiểm tra xem bảng có tồn tại trong C#
- 3. Cách kiểm tra xem tệp có tồn tại trong makefile
- 4. Kiểm tra xem tệp có tồn tại trong Yii
- 5. Kiểm tra xem tệp có tồn tại trong ksh
- 6. Kiểm tra xem phần tử có tồn tại trong DIV
- 7. SparseArray, kiểm tra xem key tồn tại
- 8. Kiểm tra xem trang web có tồn tại
- 9. Javascript: Kiểm tra xem classname tồn tại
- 10. Kiểm tra xem yếu tố tồn tại
- 11. Express, kiểm tra xem mẫu có tồn tại
- 12. Kiểm tra xem bảng truy cập có tồn tại không
- 13. CQL: cách kiểm tra xem keyspace có tồn tại không?
- 14. PDO/PHP - Kiểm tra xem hàng có tồn tại
- 15. Kiểm tra xem id DIV có tồn tại với JQuery
- 16. python: kiểm tra xem url có tồn tại jpg không.
- 17. Codeigniter & PHP kiểm tra xem phiên có tồn tại
- 18. CMake kiểm tra xem tệp cục bộ có tồn tại
- 19. Kiểm tra xem phương thức jQuery có tồn tại
- 20. Kiểm tra xem các khóa/nút JSON có tồn tại
- 21. kiểm tra xem hình ảnh có tồn tại không php
- 22. Kiểm tra xem khóa đăng ký có tồn tại không?
- 23. JQuery/Javascript: kiểm tra xem var có tồn tại không
- 24. Làm cách nào để kiểm tra xem IP có còn tồn tại trong java không?
- 25. Java, kiểm tra xem tệp thực thi có tồn tại trong môi trường PATH không
- 26. Kiểm tra xem URL có tồn tại hay không
- 27. Kiểm tra xem người dùng mysql có tồn tại
- 28. jQuery: Kiểm tra xem hình ảnh có tồn tại
- 29. Postgresql: Kiểm tra xem lược đồ có tồn tại không?
- 30. Cách kiểm tra xem tài sản có tồn tại không?
Tôi thực sự không hiểu ý tưởng đằng sau giá trị emumOf ném một ngoại lệ ... nó không có ý nghĩa gì cả. Nó sẽ thực tế hơn rất nhiều trong mọi khía cạnh nếu nó chỉ trả về NULL. – marcolopes