27. října 2008

jOpenSpace 2008 - Java vs. dynamické jazyky - více návratových hodnot v Javě (aktualizováno)

Opravil jsem špatně uvedenou ukázku Tuple3.

V záznamu z jOpenSpace na téma Java vs. dynamické jazyky jsem zaznamenal postesknutí: jediné co mi v Javě chybí je možnost, aby metoda měla více návratových hodnot. Ovšem je nutné si přiznat, že to je možné již nyní. Správný název pro objekt, který je de facto kolekcí s tou vlastností, že každý prvek je jiného typu.

Simulovat tuto funkcionalitu pomocí List<Object>, ale to není cesta správným směrem. Dále jsem našel knihovnu javatuple, ta se mi nelíbila, protože místo universálního slova tuple se třídy jmenují Tuple, Triple, ... Nakonec jsme si implementaci napsali sami, a nelitujeme.

Takže třída Tuple2 vypydá:

public class Tuple2<A, B> implements Serializable {
   protected A v1;
   protected B v2;

   private static final long serialVersionUID = -4987109478796050933L;

   public Tuple2(A v1, B v2) {
      super();
      setV1(v1);
      setV2(v2);
   }

   public A getV1() {
      return v1;
   }

   public void setV1(A v1) {
      this.v1 = v1;
   }

   public B getV2() {
      return v2;
   }

   public void setV2(B v2) {
      this.v2 = v2;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == objreturn true;
      if ((obj == null|| !(obj instanceof Tuple2)) return false;
      Tuple2<?, ?> other = (Tuple2<?, ?>obj;
      return ObjectUtils.equals(getV1(), other.getV1()) && ObjectUtils.equals(getV2(), other.getV2());
   }

   @Override
   public int hashCode() {
      int hashCode = 0;
      if (getV1() != nullhashCode += getV1().hashCode();
      hashCode *= 31;
      if (getV2() != nullhashCode += getV2().hashCode();
      return hashCode;
   }

}
Dále následuje Tuple3:

public class Tuple3<A, B, C> extends Tuple2<A, B> {
   protected C v3;

   private static final long serialVersionUID = -4987109478796050933L;

   public Tuple3(A v1, B v2, C v3) {
      super(v1, v2);
      setV3(v3);
   }

   public C getV3() {
      return v3;
   }

   public void setV3(C v3) {
      this.v3 = v3;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == objreturn true;
      if ((obj == null|| !(obj instanceof Tuple3)) return false;
      Tuple3<?, ?, ?> other = (Tuple3<?, ?, ?>obj;
      return super.equals(obj&& ObjectUtils.equals(getV3(), other.getV3());
   }

   @Override
   public int hashCode() {
      return super.hashCode() 31 ((getV3() == null: getV3().hashCode());
   }

}
Kód pro Tuple4 je již jednoduše vytvořitelný. Zbývá vytvořit implementace až kam potřebujete (my jsme se zastavili na čísle 7). Na závěr jsem vytvořil factory objekt, aby bylo vytváření pohodlnější:

public class Tuple {

   public static <A, B> Tuple2<A, B> newTuple(A a, B b) {
      return new Tuple2<A, B>(a, b);
   }

   public static <A, B, C> Tuple3<A, B, C> newTuple(A a, B b, C c) {
      return new Tuple3<A, B, C>(a, b, c);
   }

   ...

}


Když na tuto implementaci koukám, není mi jasné proč standardní knihovna neobsahuje něco podobného. I bez podpory přímo v jazyce je to řešení použitelné.

4 komentáře:

Anonymní řekl(a)...

Mensi chybka:

Dále následuje Tuple3:

public class Tuple2...

jinxx řekl(a)...

Nebo si proste a jednoduse kdyz to opravdu potrebuju, napisu specialni tridu/kontejner v tomhle pripade class AB. Dalsi varianta je vysledek vracet ciste referenci.

compute2Number(a,b)
for (number : new Number[]{a,b}) {
doStuff(number);
}

pokud je to popsane v kontraktu...

Roman Pichlík řekl(a)...

Tyhle genericke holdery se mi moc nelibi, Tuple bych akceptoval, ale Tuple7? Opravdu mi prijde lepsi udelat si objekt, ktery bude logicky ten navratovy typ zapouzdrovat.

Jira řekl(a)...

No já se zase přiznám, že znám spoustu situací, kdy budu-li dělat nějaký holder, pak to bude obyčejný data-transfer-object a to je to co nemám rád. Taková struktura z C++.

Dále si myslím, že parametry by měly především být vstupní a né výstupní (to je reakce na jinxxe).

Protože Java nemá tuple ve standardní knihovně, pak je tato možnost pro mě jedinou volbou. Přiznám se, že Tuple7 jsem nikdy nepoužil, max co vím, je Tuple4.