首先,如果我选择“语义”这个词,我会使用错误的术语。
出于各种显而易见的原因,我非常喜欢Java中的泛型。当我处理各种各样奇怪的代码时,它对我有很大的帮助,而且我经常要回到旧的东西。今天我发现自己有一个经典的参数错位错误,我可能不会在前通用时代写过 - 它们让我有点懒。
我想知道是否有一种语言功能,无论是用Java还是用其他语言中的类似概念,它都具有泛型的类型安全性,并将其扩展到一种语义安全性。具体来说,我想帮助捕获因将正确的东西放在错误的位置而导致的错误。
一个简单的例子:
Map<String, String> myMap = new HashMap<String, String>();
String myKey = "key";
String myVal = "value";
myMap.put(myVal, myKey);
没有编译器可以捕获。我想,我可以子类制作包装器给我String
Key
类型和Value
类型。我可以命名我的变量以表明它们的用途(就像我在这个例子中所做的那样)。还有什么?
所以我的问题是:
由于
答案 0 :(得分:6)
我总是使用两种不同类型的地图作为键和值,而不是相同的类型。我想有时候你想要使用与你的例子中相同的类型作为键和值。我无法想到任何具有此功能的语言。
实际上我之前使用过Clojure,对于地图,它使用了一个关键字来表示:key
,然后值就是值。它使它更清晰,但现在我正在涉及功能编程,这不是你问的问题。查看类似Lisp的语言。
我认为这只是一个没有让他们混淆的情况,Java当然不能强制执行这种检查。
最好的建议是为键和值使用不同的类型,以便编译器可以检测类型错误,或者像您一样明确地命名键和值变量。
答案 1 :(得分:4)
你不能继承String。但是,您可以创建自己的类,并使用它们。因此,例如,如果要将人员映射到角色,则可以定义类似
的人员class Person {
String id;
String firstName;
String lastName;
...
}
和
这样的角色class Role {
int id;
String name;
}
(注意这些将需要定义一个equals和hashcode方法)
并且具有从人到角色的映射:
Map<Person, Set<Role>> myMap = new HashMap<Person, Set<Role>>();
以便类型系统强制执行您可以放在哪里(而不是将字符串映射到整数组)。不确定这是什么,但“域对象”和“抽象数据类型”似乎相关。
在没有类型检查的情况下,后备是编写单元测试。
答案 2 :(得分:4)
您可以使用更广泛的类型系统,避免在参数列表中使用相同的类型。
即。
Map<Key, Value> myMap = new HashMap<Key, Value>();
Key myKey = // some key
Value myVal = // some value
myMap.put(myVal, myKey); //compiler error
在某种程度上,您需要解释概念以及它们如何与操作交互以使语言检查任何内容,并对是否有任何替代方法感兴趣。
答案 3 :(得分:2)
我不知道任何可以解决这个问题的语言概念。基本上你要求的是一个思维阅读编译器。即。
我唯一的想法是语言可以强加语法约束来模仿所需的语义约束。例如,它可能要求您命名要用作键“key_somename_”的变量,以及用于值的变量。有点改进,但它限制了程序员。
如果您真的担心它,您可以在Java中扩展Map以仅接受实现虚拟“密钥”接口的类型,并生成每次需要密钥类时实现该接口的子类型。
答案 4 :(得分:2)
这很糟糕但是有效:
public static <K extends String,V extends String> void test() {
K key = (K) "foo";
V val = (V) "bar";
Map<K,V> map = new HashMap<K,V>();
map.put(key,val);
}
现在它更有趣了:
// The whole code is using type parameters like this:
public static <K extends String,V extends String> void test(K key, V value) {
Map<K,V> map = new HashMap<K,V>();
map.put(key,val);
}
// At the end, use the real type (K=String, V=String);
public static void main(String[) args) {
test<String,String>("foo","bar");
};