我喜欢Java具有Map的方式,您可以在其中定义地图中每个条目的类型,例如<String, Integer>

我要寻找的是一种类型的集合,其中集合中的每个元素都是一对值。该对中的每个值都可以具有自己的类型(例如上面的String和Integer示例),该类型在声明时定义。

集合将保持其给定顺序,并且不会将值之一视为唯一键(如在地图中)。

基本上,我希望能够定义<String,Integer>类型或任何其他2种类型的ARRAY。

我意识到我可以创建一个只包含2个变量的类,但这似乎太冗长了。

我也意识到我可以使用2D数组,但是由于需要使用不同的类型,我不得不将它们制成OBJECT数组,然后我必须将所有时间。

我只需要在集合中存储对,因此每个条目只需要两个值。如果不走上课路线,是否存在这样的东西?谢谢!

评论

我想知道番石榴还可以为此上一堂课。

番石榴是非常好的对偶,而Google的员工则尽力创造出更好的替代品-自动/值。它使您可以使用适当的equals / hashCode语义轻松创建类型良好的值类型类。您再也不需要配对类型!

#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)创建IntIntPairPrimitiveTuples.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 listOfTuple。如何使用listOfTuple.add()?如果我愿意-listOfTuple.add(Pair );,则将无法工作。提前致谢。

– 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>


#8 楼

您可以编写一个通用的Pair 类,并在数组或列表中使用它。是的,您必须编写一个类,但是您可以为所有类型重用同一类,因此只需要执行一次即可。

评论


我希望看到一个例子!

–DivideByHero
09年2月6日在17:18

丹,关于此的坏事是不可能接受例如因为类型擦除,只有Pair s,不是吗?但是Java也是如此...

–约翰尼斯·魏斯(Johannes Weiss)
09年2月6日在17:26

有趣,约翰内斯。 java.sun.com/docs/books/tutorial/java/generics/erasure.html

– JMD
09年2月6日在17:42

我认为这不适用于纯数组,但绝对适用于其他Collections。

– Outlaw程序员
09年2月6日在17:49

@Outlaw程序员:好的,您可以将其与数组一起使用,但是这很丑陋,因为您必须使用hack来创建通用数组。

–丹·代尔
09年2月6日在17:59

#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));