Javaでタプルを実現してみる

いつもパスタを茹でる量を誤り、満腹で就寝につく日々を繰り返す今日この頃、いかがお過ごしでしょうか?どうも、ボクです。

というわけで、今回は、タプルについて。言語はJavaです。そんでは、レッツトライ~。

 

タプルとは?

Wikipediaさんにお聞きしましょう。

タプルまたはチュープルtuple)とは、複数の構成要素からなる組を総称する一般概念。

数学計算機科学などでは通常、順序付けられた対象の並びを表すために用いられる。個別的には、n 個でできた組を英語で「n-tuple」と書き、日本語に訳す場合は通常「n 」としている。タプルの概念そのものもと呼ばれる場合がある。なお、 n-tuple は数学のタプルを意味するほか、同様に doubletriple などの拡張として倍数詞の表現にも利用される(詳細は「倍#西洋数学における n 倍を表す表現」を参照)。

タプル - Wikipedia

⇧  う~ん...よく分からん...

そんでは、プログラミング的な意味合いはと言うと、 

タプル型

型システム的には、代数的データ型でいう直積型そのものであり、C#C++HaskellKotlinMLPythonScalaTypeScript といった多くのプログラミング言語にタプル型がある。いくつかは (x, y) といったような構文でタプル型の値を直接記述できる。

動的な型付けを持つ言語では、コンテナ型を使うことで済まさせている場合もある。一方でPythonのように、長さを後から変えられないばかりでなく要素を変えることもできないというような、タプル専用のオブジェクトを用意している場合もある。

静的な型付けを持つ言語の場合、リスト型やコンテナ型の要素は、基本的になんらかの「同じ」型でなければならないので、それらの集積型をタプルの目的に流用することは不可能であり、そのためこの節の冒頭のようにタプルないし同等のものをサポートしていることが多い。

タプル - Wikipedia

⇧  こちらも、よく分からんですが、少なくとも、Java には標準では用意されていないらしい(涙)。

 

qiita.com

⇧  上記サイト様によりますと、スタック・オーバーフローの回答で、Java SE8では標準APIとしてTupleは、存在しないと。

stackoverflow.com

⇧  上記サイト様で言及されていますね。

ちなみに、Pair は、2組しか扱えないもので、Tupleは、任意の組(3組以上可能)を扱えるということらしい、Java SE8の標準には存在しないけど。

なんで、Java SE8の標準でTupleが存在しないかと言うと、実現するには、いろいろ面倒くさいことが必要になるってことが原因ってことですかね...

 

By the way、そんじゃ、Tupleを使うことで何が嬉しいのか?

使い道として多いのが、戻り値として複数の型を返却できるってことみたいです。

qiita.com

⇧  Wikipediaさんにもあったように、ScalaJVM上で動作する) では、標準でTupleが使えるようですね。

 

JavaでTupleを実現してみる

そんじゃ、標準ライブラリしか使えないプロジェクトで、Tuple的なものを実現したい場合はどうすれば?

qiita.com

⇧  上記サイト様によりますと、自作クラスでTupleを実現していけば良いじゃない~ということのようです。 

そんでは、上記サイト様を参考に作ってみましょう。

Eclipseを起動し、適当なJavaプロジェクトを作成し、クラスも作成で。

f:id:ts0818:20190421204744p:plain

各クラスはこんな感じ。

Profile.java

package dto;

import java.util.Map;

public class Profile {

  private String name;
  
  private int age;
  
  private String from;
  
  private String hobby;
  
  public Profile() {
    
  }
  
  public Profile(Map<String, Object> map) {
    this.name = (String)map.get("name");
    this.age = (int)map.get("age");
    this.from = (String)map.get("from");
    this.hobby = (String)map.get("hobby");  
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public String getFrom() {
    return from;
  }

  public void setFrom(String from) {
    this.from = from;
  }

  public String getHobby() {
    return hobby;
  }

  public void setHobby(String hobby) {
    this.hobby = hobby;
  }
}

BruceLee.java

package dto;

import java.util.Map;

public class BruceLee extends Profile {
  
  private Profile profile;
  
  private String jikundo;
  
  public BruceLee() {
    
  }

  public BruceLee(Map<String, Object> map) {
    super(map);
  }
  
  public Profile getProfile() {
    return profile;
  }

  public void setProfile(Profile profile) {
    this.profile = profile;
  }

  public String getJikundo() {
    return jikundo;
  }

  public void setJikundo(String jikundo) {
    this.jikundo = jikundo;
  }
}

IppMan.java

package dto;

import java.util.Map;

public class IppMan extends Profile {

  private Profile profile;
  
  private String eisyunken;
  
  public IppMan() {
    
  }
  
  public IppMan(Map<String, Object> map) {
    super(map);  
  }

  public Profile getProfile() {
    return profile;
  }

  public void setProfile(Profile profile) {
    this.profile = profile;
  }
  
  public String getEisyunken() {
    return eisyunken;
  }

  public void setEisyunken(String eisyunken) {
    this.eisyunken = eisyunken;
  }
}

SammoHung.java

package dto;

import java.util.Map;

public class SammoHung extends Profile {

  private Profile profile;
  
  private String kouken;
  
  public SammoHung() {
    
  }
  
  public SammoHung(Map<String, Object> map) {
    super(map);
  }

  public Profile getProfile() {
    return profile;
  }

  public void setProfile(Profile profile) {
    this.profile = profile;
  }

  public String getKouken() {
    return kouken;
  }

  public void setKouken(String kouken) {
    this.kouken = kouken;
  }
}

WongFeiHung.java

package dto;

import java.util.Map;

public class WongFeiHung extends Profile {

  private Profile profile;
  
  private String koukaken;
  
  public WongFeiHung() {
    
  }
  
  public WongFeiHung(Map<String, Object> map) {
    super(map);
  }

  public Profile getProfile() {
    return profile;
  }

  public void setProfile(Profile profile) {
    this.profile = profile;
  }

  public String getKoukaken() {
    return koukaken;
  }

  public void setKoukaken(String koukaken) {
    this.koukaken = koukaken;
  }
}

TupleUtil.java

package util;

public class TupleUtil {

  public static class Pair<A, B> {
    
    public final A a;
    public final B b;

    public Pair(A a, B b) {
      this.a = a;
      this.b = b;
    }

    private static boolean eq(Object o1, Object o2) {
      // オブジェクトがNULLでない、かつ、等しい場合はfalseを返す
      return o1 == null ? o2 == null : o1.equals(o2);
    }

    private static int hc(Object o) {
      // オブジェクトのハッシュコード値を返す
      return o == null ? 0 : o.hashCode();
    }

    @Override
    public boolean equals(Object o) {
      if (!(o instanceof Pair)) {
        return false;
      }
      Pair<?, ?> rhs = (Pair<?, ?>) o;
      return eq(this.a, rhs.a) && eq(this.b, rhs.b);
    }

    @Override
    public int hashCode() {
      return hc(this.a) ^ hc(this.b);
    }

    @Override
    public String toString() {
      return "[" + (this.a != null ? this.a.toString() : "null") + " : "
          + (this.b != null ? this.b.toString() : "null") + "]";
    }

  }

  public static class Tuple01<A> extends Pair<A, Object> {
    public Tuple01(A a) {
      super(a, null);
    }
  }

  public static class Tuple02<A, B> extends Pair<A, Tuple01<B>> {
    public Tuple02(A a, B b) {
      super(a, new Tuple01<>(b));
    }
  }

  public static class Tuple03<A, B, C> extends Pair<A, Tuple02<B, C>> {
    public Tuple03(A a, B b, C c) {
      super(a, new Tuple02<>(b, c));
    }
  }

  public static class Tuple04<A, B, C, D> extends Pair<A, Tuple03<B, C, D>> {
    public Tuple04(A a, B b, C c, D d) {
      super(a, new Tuple03<>(b, c, d));
    }
  }

  public static class Tuple05<A, B, C, D, E> extends Pair<A, Tuple04<B, C, D, E>> {
    public Tuple05(A a, B b, C c, D d, E e) {
      super(a, new Tuple04<>(b, c, d, e));
    }
  }

  public static class Tuple06<A, B, C, D, E, F> extends Pair<A, Tuple05<B, C, D, E, F>> {
    public Tuple06(A a, B b, C c, D d, E e, F f) {
      super(a, new Tuple05<>(b, c, d, e, f));
    }
  }

  public static class Tuple {
    public static <A> Tuple01<A> of(A a) {
      return new Tuple01<A>(a);
    }

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

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

    public static <A, B, C, D> Tuple04<A, B, C, D> of(A a, B b, C c, D d) {
      return new Tuple04<A, B, C, D>(a, b, c, d);
    }

    public static <A, B, C, D, E> Tuple05<A, B, C, D, E> of(A a, B b, C c, D d, E e) {
      return new Tuple05<A, B, C, D, E>(a, b, c, d, e);
    }

    public static <A, B, C, D, E, F> Tuple06<A, B, C, D, E, F> of(A a, B b, C c, D d, E e, F f) {
      return new Tuple06<A, B, C, D, E, F>(a, b, c, d, e, f);

    }
  }
}

AppEndPoint.java

package main;

import java.util.HashMap;
import java.util.Map;

import dto.BruceLee;
import dto.IppMan;
import dto.SammoHung;
import dto.WongFeiHung;
import util.TupleUtil.Tuple;
import util.TupleUtil.Tuple04;

public class AppEndPoint {

  public static void main(String[] args) {
    // 
    Map<String, Object> map01 = new HashMap<String, Object>() {
      {
        put("name", "葉問");
        put("age", 79);
        put("from", "清広東省仏山");
        put("hobby", "功夫");        
      }
    };
    
    Map<String, Object> map02 = new HashMap<String, Object>() {
      {
        put("name", "李小龍");
        put("age", 32);
        put("from", "イギリス領香港九龍");
        put("hobby", "功夫");        
      }
    };

    Map<String, Object> map03 = new HashMap<String, Object>() {
      {
        put("name", "洪金寶");
        put("age", 67);
        put("from", "イギリス領香港");
        put("hobby", "功夫");        
      }
    };

    Map<String, Object> map04 = new HashMap<String, Object>() {
      {
        put("name", "黄 飛鴻");
        put("age", 78);
        put("from", "清広東省広州府南海県西樵嶺西禄舟村");
        put("hobby", "功夫");        
      }
    };

    IppMan ippMan = new IppMan(map01);
    BruceLee bruceLee = new BruceLee(map02);
    SammoHung sammoHung = new SammoHung(map03);
    WongFeiHung wongFeiHung = new WongFeiHung(map04);
    
    Tuple04<IppMan, BruceLee, SammoHung, WongFeiHung> tuple = Tuple.of(ippMan, bruceLee, sammoHung, wongFeiHung);
    System.out.println(tuple.a.getName() + "(イップマン)");
    System.out.println(tuple.b.a.getName() + "(ブルース・リー)");
    System.out.println(tuple.b.b.a.getName() + "(サモ・ハン・キンポー)");
    System.out.println(tuple.b.b.b.a.getName() + "(ウォン・フェイフォン)");

  }
}

そしたらば、実行で。

f:id:ts0818:20190421205933p:plain

f:id:ts0818:20190421210007p:plain

とりあえず、上手く複数の戻り値を受け取れたということで...う~ん、使いどころが分からん...。TupleUtil.javaのタプルの数を増やせば、もっと返却できる型は増えるかと。今回は、見本と同じく、Tuple06 まで実装してます。

全然関係ないけど、映画『イップ・マン4』で、ドニー・イェンが主演のシリーズは完結してしまうとか(涙)。

theriver.jp

 

今回はこのへんで。