如何使用从数据库中读取的类型以及如何在代码中提供类型安全?
前提
给定是一个包含各种类型列的数据库表。列"A"包含字符串值"A"、"B"、"C"。列"B"包含字符串值"X"、"Y"、"Z"。
示例用法
为了保证类型安全,我宁愿将这些值包装在枚举周围并使用这些类型,而不是直接将这些值用作字符串。
像这样:
public class TypeSafetyExample {
/**
* TypeA: map string type to enum type.
*/
public enum TypeA {
A("A"),
B("B"),
C("C");
String id;
TypeA( String id) {
this.id = id;
}
public static TypeA get( String id) {
for( TypeA item: EnumSet.allOf(TypeA.class)) {
if( item.id.equals(id)) {
return item;
}
}
throw new IllegalArgumentException("Unsupported enum id: " + id);
}
}
/**
* TypeB: map string type to enum type and give it some other attribute.
*/
public enum TypeB {
X("X", true),
Y("Y", true),
Z("Z", false);
String id;
boolean someAttribute;
TypeB( String id, boolean someAttribute) {
this.id = id;
this.someAttribute = someAttribute;
}
public boolean isSomeAttribute() {
return this.someAttribute;
}
public static TypeB get( String id) {
for( TypeB item: EnumSet.allOf(TypeB.class)) {
if( item.id.equals(id)) {
return item;
}
}
throw new IllegalArgumentException("Unsupported enum id: " + id);
}
}
/**
* Object using enums as types.
*/
public static class MyObjectTyped {
TypeA typeA;
TypeB typeB;
public String toString() {
return "Type A: " + typeA + ", Type B: " + typeB;
}
}
/**
* Object using strings as types.
*/
public static class MyObjectUntyped {
String typeA;
String typeB;
public String toString() {
return "Type A: " + typeA + ", Type B: " + typeB;
}
}
/**
* Example usage.
* @param args
*/
public static void main(String[] args) {
MyObjectTyped objTyped;
MyObjectUntyped objUntyped;
// ... here we would read data from the database and create our typed objects ...
objTyped = new MyObjectTyped();
objTyped.typeA = TypeA.get( "A");
objTyped.typeB = TypeB.get( "X");
System.out.println( objTyped); // Type A: A, Type B: X
objTyped = new MyObjectTyped();
objTyped.typeA = TypeA.get( "A");
objTyped.typeB = TypeB.get( "?"); // Runtime Error during database read: java.lang.IllegalArgumentException: Unsupported enum id: ?
objUntyped = new MyObjectUntyped();
objUntyped.typeA = "???"; // no error at all, probably we'll get a runtime error or some inconsistency later, but never during database loading
objUntyped.typeB = "???"; // no error at all, probably we'll get a runtime error or some inconsistency later, but never during database loading
System.exit(0);
}
}
基本上,对于每种类型,都会创建一个枚举,并将数据库字符串类型映射到该枚举。在 java 代码中,只使用枚举,从不使用字符串。
枚举的优点:
- 从数据库加载期间的一致性检查
枚举的缺点:
- 每当添加新类型时都需要更改代码
字符串的优点:
- 添加新类型时无需更改代码
字符串的缺点:
- 无类型安全。数据库可以包含任何内容。运行时可能会出现错误。
您如何看待这些概念?你更喜欢哪一个?还是有更好的方法?我宁愿坚持类型安全,因为代码的稳定性是值得的。另一方面,每当添加新类型时进行代码更改也不是好的做法。
感谢您的意见!
这完全取决于您如何使用这些字符串。代码的逻辑是否取决于实际值,或者它只是您从数据库中读取的内容,也许以某种方式转换并呈现给用户或发送给其他消费者?
如果是前者,则可能需要枚举。
另请注意,如果要确保字符串属于已知的有效集,则可以在数据库级别强制实施约束。因此,"数据库可以包含任何内容"并不是真的。
一般来说,如果你正在使用数据库,它应该是你放在那里的数据的一致性和有效性的"事实来源"。这就是数据库的用途,也是他们擅长的。在数据存储中扔垃圾,并依靠应用程序代码在出厂时对其进行清理根本不是一个好主意。