<String, Integer>
。 我要寻找的是一种类型的集合,其中集合中的每个元素都是一对值。该对中的每个值都可以具有自己的类型(例如上面的String和Integer示例),该类型在声明时定义。
集合将保持其给定顺序,并且不会将值之一视为唯一键(如在地图中)。
基本上,我希望能够定义
<String,Integer>
类型或任何其他2种类型的ARRAY。 我意识到我可以创建一个只包含2个变量的类,但这似乎太冗长了。
我也意识到我可以使用2D数组,但是由于需要使用不同的类型,我不得不将它们制成OBJECT数组,然后我必须将所有时间。
我只需要在集合中存储对,因此每个条目只需要两个值。如果不走上课路线,是否存在这样的东西?谢谢!
#1 楼
Pair类是这些“大型”泛型示例之一,很容易自己编写。例如,在我的头上:public class Pair<L,R> {
private final L left;
private final R right;
public Pair(L left, R right) {
assert left != null;
assert right != null;
this.left = left;
this.right = right;
}
public L getLeft() { return left; }
public R getRight() { return right; }
@Override
public int hashCode() { return left.hashCode() ^ right.hashCode(); }
@Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) return false;
Pair pairo = (Pair) o;
return this.left.equals(pairo.getLeft()) &&
this.right.equals(pairo.getRight());
}
}
是的,它存在于网络上的多个位置,具有不同程度的完整性和功能。 (我上面的示例旨在保持不变。)
评论
我喜欢这样,但是您如何看待公开左右字段呢?很显然,Pair类永远不会有任何逻辑关联,并且所有客户端都需要访问“ left”和“ right”,所以为什么不那么简单呢?
– Outlaw程序员
09年2月6日在17:39
嗯...不,不会。这些字段被标记为最终字段,因此无法重新分配。而且它不是线程安全的,因为“ left”和“ right”可能是可变的。除非getLeft()/ getRight()返回防御性副本(在这种情况下没有用),否则我看不出有什么大不了的。
– Outlaw程序员
09年2月6日在17:46
请注意,如果左右互换,则hashCode()照原样提供相同的值。也许:long l = left.hashCode()* 2654435761L; return(int)l +(int)(l >>> 32)+ right.hashCode();
– Karmakaze
2012年4月28日在21:40
因此,如果我正确理解,推出一个简单的配对类会产生语法错误,subpar hashCode方法,空指针异常,没有compareTo方法,设计问题……并且人们仍然主张推出此类,因为它存在于Apache公共领域。请,如果不想包含JAR,只需复制代码即可,但不要重新发明轮子了!
–cquezel
13年3月18日在20:20
您是什么意思,“足够容易自己编写”?那是可怕的软件工程。是否在MyPair和SomeoneElsesPair之间转换的N ^ 2适配器类是否也足够容易编写自己编写?
– djechlin
13年11月1日在18:59
#2 楼
AbstractMap.SimpleEntry您正在寻找的容易之处:
java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();
如何填充?
java.util.Map.Entry<String,Integer> pair1=new java.util.AbstractMap.SimpleEntry<>("Not Unique key1",1);
java.util.Map.Entry<String,Integer> pair2=new java.util.AbstractMap.SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);
这可以简化为:
Entry<String,Integer> pair1=new SimpleEntry<>("Not Unique key1",1);
Entry<String,Integer> pair2=new SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);
,借助
createEntry
方法,可以进一步降低冗长程度: pairList.add(createEntry("Not Unique key1", 1));
pairList.add(createEntry("Not Unique key2", 2));
由于
ArrayList
不是最终的,因此可以将其归类以公开of
方法(以及前面提到的createEntry
方法),从而使语法简洁:TupleList<java.util.Map.Entry<String,Integer>> pair = new TupleList<>();
pair.of("Not Unique key1", 1);
pair.of("Not Unique key2", 2);
评论
仅供参考:这表明SimpleEntry有一个兄弟类,省略了setValue方法是不可变的。因此,名称为SimpleImmutableEntry。
–罗勒·布尔克
16-4-4在23:49
这比自我实现更好。易于实现这一事实并不是每次都实现的借口。
– Pevogam
17年5月5日在18:53
我不会认为它是“标准”。 Entry应该是一个键-值对,这样做很好。但是它有一个真正的元组的弱点。例如,SimpleEntry中的哈希码实现仅对元素的代码进行异或运算,因此散列为与相同的值。元组的实现通常按字典顺序排序,但是SimpleEntry不实现Comparable。所以要小心...
–基因
17年1月16日在20:22
感谢@Gene提出了哈希码问题,这让我感到惊讶。 XOR的使用还意味着其他一系列冲突,包括key == value的所有对将产生相同(零)的哈希码。
–neilireson
7月2日13:17
#3 楼
Java 9+在Java 9中,您可以简单地编写:
Map.entry(key, value)
创建不可变对。
注意:此方法不允许键或值为null。例如,如果要允许空值,则要将其更改为:
Map.entry(key, Optional.ofNullable(value))
。Java 8+
在Java 8中,您可以可以使用更通用的
javafx.util.Pair
来创建一个不变的,可序列化的对。此类确实允许空键和空值。 (在Java 9中,此类包含在javafx.base
模块中)。编辑:从Java 11开始,JavaFX已与JDK分离,因此您需要其他Maven工件org.openjfx:javafx-base。Java 6+
在Java 6及更高版本中,对于不可变对,可以使用更详细的
AbstractMap.SimpleImmutableEntry
,对于可以更改其值的对,可以使用AbstractMap.SimpleEntry
。这些类还允许空键和空值,并且可序列化。Android
如果您是为Android编写的,则只需使用
Pair.create(key, value)
创建不可变的对。Apache Commons
Apache Commons Lang
提供了有用的Pair.of(key, value)
来创建一个不变的,可比较的,可序列化的对。Eclipse集合
如果您使用包含原始的对,则Eclipse Collections提供了一些非常有效的原始对类,这些类将避免所有低效的自动装箱和自动拆箱。
例如,您可以使用
PrimitiveTuples.pair(int, int)
创建IntIntPair
或PrimitiveTuples.pair(float, long)
创建FloatLongPair
。 Project Lombok
使用Project Lombok,您只需编写以下内容即可创建不可变对类:
@Value
public class Pair<K, V> {
K key;
V value;
}
Lombok会在生成的字节码中自动为您填充构造函数,getter,
equals()
,hashCode()
和toString()
方法。如果要使用静态工厂方法而不是构造函数(例如Pair.of(k, v)
),则只需将批注更改为:@Value(staticConstructor = "of")
。否则
如果上述解决方案都无法解决,您可以简单地复制并粘贴以下代码(与接受的答案中列出的类不同,该代码可防止NullPointerExceptions):
import java.util.Objects;
public class Pair<K, V> {
public final K key;
public final V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public boolean equals(Object o) {
return o instanceof Pair && Objects.equals(key, ((Pair<?,?>)o).key) && Objects.equals(value, ((Pair<?,?>)o).value);
}
public int hashCode() {
return 31 * Objects.hashCode(key) + Objects.hashCode(value);
}
public String toString() {
return key + "=" + value;
}
}
评论
但是,JavaFX仅限于桌面,对非桌面环境(例如服务器)增加了不必要的依赖。
–foo
17年6月29日在17:19
Eclipse Collections还具有对象的Pair接口,可以通过调用Tuples.pair(object1,object2)实例化该接口。 eclipse.org/collections/javadoc/9.2.0/org/eclipse/collections / ...
–唐纳德·拉布(Donald Raab)
18-09-26在2:43
这感觉像是最真实的Java风格的答案。所有可用的实现。非常详尽,非常感谢!
–迈克
18-10-6在22:35
嗨@Hans我正在使用列表List
– Me_developer
19年1月8日在10:47
android版本在单元测试中不可用,这使其并没有真正的用处...
–OznOg
19年4月11日在8:09
#4 楼
Map.Entry
这些内置类也是一个选项。两者均实现
Map.Entry
接口。AbstractMap.SimpleEntry
AbstractMap.SimpleImmutableEntry
评论
它们不仅是一个选择,而且是正确的答案。我认为有些人只喜欢重新发明轮子。
–CurtainDog
2012年6月28日在1:42
#5 楼
Apache通用lang3在该线程中提到了Pair类和其他几个库。Java中C ++ Pair示例符合您原始问题的要求:
List<Pair<String, Integer>> myPairs = new ArrayList<Pair<String, Integer>>();
myPairs.add(Pair.of("val1", 11));
myPairs.add(Pair.of("val2", 17));
//...
for(Pair<String, Integer> pair : myPairs) {
//following two lines are equivalent... whichever is easier for you...
System.out.println(pair.getLeft() + ": " + pair.getRight());
System.out.println(pair.getKey() + ": " + pair.getValue());
}
评论
如果可以使用Apache Commons,这是最简单的选择。
–基普
16年2月2日在14:55
#6 楼
对于为Android开发的任何人,都可以使用android.util.Pair。 :)#7 楼
那么“ Apache Commons Lang 3”Pair
类及其相对子类又如何呢? import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
...
@SuppressWarnings("unchecked")
Pair<String, Integer>[] arr = new ImmutablePair[]{
ImmutablePair.of("A", 1),
ImmutablePair.of("B", 2)};
// both access the 'left' part
String key = arr[0].getKey();
String left = arr[0].getLeft();
// both access the 'right' part
Integer value = arr[0].getValue();
Integer right = arr[0].getRight();
ImmutablePair
是一个特定的子类,不允许修改该对中的值,但是还有其他具有不同语义的实现。这些是Maven坐标(如果需要)。 <dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
#9 楼
扩展其他答案,通用不可变对应该具有静态方法,以避免因调用构造函数而使代码混乱:class Pair<L,R> {
final L left;
final R right;
public Pair(L left, R right) {
this.left = left;
this.right = right;
}
static <L,R> Pair<L,R> of(L left, R right){
return new Pair<L,R>(left, right);
}
}
如果将静态方法命名为“ “ of”或“ pairOf”的代码变得流畅,您可以编写以下代码:
list.add(Pair.of(x,y)); // my preference
list.add(pairOf(x,y)); // use with import static x.y.Pair.pairOf
真可惜,核心Java库如此稀疏,以至于您必须使用commons-lang或其他第3方来进行此类基本操作。升级到Scala的另一个原因...
#10 楼
我想问问您是否只想使用List<Pair<T, U>>
?但是,当然,JDK没有Pair <>类。但是很快谷歌在Wikipedia和forums.sun.com上都找到了。干杯#11 楼
正如您所描述的,首选的解决方案是成对列表(即列表)。要实现此目的,您将创建一个Pair类以供您的集合使用。这是一个有用的实用程序类,可添加到您的代码库中。
Sun JDK中提供与典型Pair类相似功能的最接近类是AbstractMap.SimpleEntry。您可能会使用此类而不是创建自己的Pair类,尽管您将不得不承受一些尴尬的限制,而且我认为大多数人会因为不是真正的SimpleEntry角色而对此感到不满意。例如,SimpleEntry没有“ setKey()”方法,也没有默认构造函数,因此您可能会发现它太局限了。
请记住,集合被设计为包含单个类型的元素。相关实用程序接口(例如Map)实际上不是集合(即Map未实现Collection接口)。一对也不会实现Collection接口,但是显然在构建更大的数据结构中是有用的类。
评论
我发现此解决方案比使用通用Pair
–绍尔
14-10-15在10:46
#12 楼
这基于JavaHelp4u的代码。较少冗长,并显示了如何在一行中完成操作以及如何遍历所有内容。
//======> Imports
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
//======> Single Entry
SimpleEntry<String, String> myEntry = new SimpleEntry<String, String>("ID", "Text");
System.out.println("key: " + myEntry.getKey() + " value:" + myEntry.getValue());
System.out.println();
//======> List of Entries
List<Entry<String,String>> pairList = new ArrayList<>();
//-- Specify manually
Entry<String,String> firstButton = new SimpleEntry<String, String>("Red ", "Way out");
pairList.add(firstButton);
//-- one liner:
pairList.add(new SimpleEntry<String,String>("Gray", "Alternate route")); //Ananomous add.
//-- Iterate over Entry array:
for (Entry<String, String> entr : pairList) {
System.out.println("Button: " + entr.getKey() + " Label: " + entr.getValue());
}
#13 楼
Apache Crunch也具有Pair
类:http://crunch.apache.org/apidocs/0.5.0/org/apache/crunch/Pair.html
#14 楼
只需创建一个类似class tuples
{
int x;
int y;
}
的类,然后创建该元组对象的列表
List<tuples> list = new ArrayList<tuples>();
,这样您就可以也以相同的方式实现其他新的数据结构。
#15 楼
我的意思是,即使Java中没有Pair
类,也有一些类似的东西:Map.Entry
Map.Entry文档
这是
HashMap
的(简化了很多),或实际上任何Map
商店。您可以创建
Map
实例,在其中存储您的值并获取条目集。您最终会得到一个有效的Set<Map.Entry<K,V>>
。因此:
public static void main(String []args)
{
HashMap<String, Integer> values = new HashMap<String,Integer>();
values.put("A", 235);//your custom data, the types may be different
//more data insertions....
Set<Map.Entry<String,Integer>> list = values.entrySet();//your list
//do as you may with it
}
评论
此选项存在唯一键的问题。假设您具有人物属性(例如{{person1,“蓝眼睛”),(person1,“红发”,(person2,“近视”),(person2,“快速思考”))),无法将它们成对存储在地图中,因为每个人都是地图的关键,并且每个人只允许一个属性。
–manuelvigarcia
16-10-27在10:13
#16 楼
Spring在Data Utils软件包中具有Pair<S,T>
类型org.springframework.data.util
Pair<String,Integer> pair = Pair.of("Test", 123);
System.out.println(pair.getFirst());
System.out.println(pair.getSecond());
#17 楼
com.sun.tools.javac.util.Pair呢?评论
此类型在tools.jar中-javac编译器的“ Sun”实现的一部分。它仅作为JDK的一部分分发,可能不存在于其他供应商实现中,并且不太可能成为公共API的一部分。
– McDowell
2012年6月19日在8:27
#18 楼
首先,在谈论键/值对时,我想到的是属性类,您可以在其中保存项目并将其加载到流/文件中。#19 楼
在Project Reactor(io.projectreactor:reactor-core)中,对n-Tuples有高级支持:Tuple2<String, Integer> t = Tuples.of("string", 1)
您可以获得
t.getT1(), t.getT2(), ...
,尤其是使用Stream或Flux时,您可以甚至映射元组元素:Stream<Tuple2<String, Integer>> s;
s.map(t -> t.mapT2(i -> i + 2));
评论
我想知道番石榴还可以为此上一堂课。番石榴是非常好的对偶,而Google的员工则尽力创造出更好的替代品-自动/值。它使您可以使用适当的equals / hashCode语义轻松创建类型良好的值类型类。您再也不需要配对类型!