元組類型,即 Tuple 常在腳本語言中出現,例如 Scala 的 ("Unmi", "china@qq.com", "blahbla")。元組可認為是象數組一樣的容器,它的目的是讓你方便構造和引用,例如 Pair 可認為是一個只能存兩個元素的元組,像是個 Map; 真正的元組應該是可以任意多個元素的容器,繞來繞去,它還是數組,或列表,所以我們實現上還是要借助於數組或是列表。
先看 Scala 中什么是元組:
val tuple = ("Unmi", "fantasia@sina.com", "blahblah...")
println(tuple._1) //輸出 Unmi
Scala 中訪問從 1 開始,用 ._1 方式來訪問其中的元素。
場景:當在一個方法中, 你需要返回幾個對象,這幾個對象的類型一致,你可以返回一個數組;如果幾個對象的類型不同呢,當然你可以返回一個Object[]數組,可是這樣在使用結果數組的時候,就需要強轉對象的類型,會導致類型不安全;也可以定義一個dto,當多個場景下需要使用的不同,需要定義多個dto,這樣會類爆炸,而且重用率極低;在非常接近Java語言的Scala里有元組的定義:val t = (1, 3.14, "Fred"),就是一個不同類型的數據放到一個線性集合里,在Java里我們可以模擬出一個類似的結構,以適合上面的場景。
示例一:
參照於此,寫出一個 Java 版本的 Tuple,為增長你的鍵盤的使用壽命,我們把方法名也縮短了,例如 make 縮寫為 mk,引用元素的方法名為 _,仍然保持 Java 的習慣,索引從 0 開始:
package com.sf.tuple; /** * A simple java tuple */ public class Tuple<A> { /** * 靜態方法 * * @param args * @return */ public static <A> Tuple mk(A... args) { return new Tuple(args); } private A[] items; /** * 私有構造函數 * * @param items */ private Tuple(A[] items) { this.items = items; } public A _(int index) { if (index < 0 || items == null || index > items.length - 1) { return null; } return items[index]; } public static void main(String[] args) { Tuple<String> t = Tuple.mk("Unmi", "china@qq.com"); System.out.println(t._(0)); // 輸出 Unmi System.out.println(t._(1)); // 輸出 china@qq.com } }
結果:
Unmi
china@qq.com
代碼間加了一個 main 測試方法,上面的代碼輸出什么無需多說了。
這樣就實現了 Tuple.mk() 后接任意多個參數來構造一個 Tuple 對象。
示例二:
package com.sf; import com.google.common.base.Optional; abstract class Tuple { public static void main (String[] args) { Tuple tuple2 = Tuple.<String, Integer>of("hello", 1); Tuple tuple3 = Tuple.<String, Integer, String>of("hello", 1, "hi"); System.out.println(tuple2._1().get() + "|" + tuple2._2().get()); System.out.println(tuple3._1().get() + "|" + tuple3._2().get() + "|" + tuple3._3().get()); } public static <E, T> Tuple of (E e, T t) { return new Tuple2(e, t); } public static <E, T, K> Tuple of (E e, T t, K k) { return new Tuple3(e, t, k); } public abstract <E> Optional<E> _1 (); public abstract <E> Optional<E> _2 (); public abstract <E> Optional<E> _3 (); } class Tuple2<E, T> extends Tuple { private E e; private T t; Tuple2 (E e, T t) { this.e = e; this.t = t; } @Override public Optional<E> _1 () { return Optional.of(e); } @Override public Optional<T> _2 () { return Optional.of(t); } @Override public <E> Optional<E> _3() { return Optional.absent(); } } class Tuple3<E, T, K> extends Tuple { private E e; private T t; private K k; Tuple3 (E e, T t, K k) { this.e = e; this.t = t; this.k = k; } public Optional<E> _1 () { return Optional.of(e); } public Optional<T> _2 () { return Optional.of(t); } public Optional<K> _3 () { return Optional.of(k); } }
結果:
hello|1
hello|1|hi
上面的代碼中定義了三個類,父類為抽象類Tuple,此父類就是定義了一些模板方法,方法名有點不像Java方法名的命名規范,那是模仿scala里的方法命名,Tuple類沒有其他作用,只是提供靜態方法,創建Tuple的之類充當容器,提供多個容器的入口;
Tuple2<E,T>可以充當兩個對象的容器,該容器內保持兩個對象的引用,通過方法_1(), _2()獲取第一個和第二個對象的值,在此並沒有直接返回對象,而是返回一個Optional對象,這是提醒使用返回值的方法做非Null檢查;
Tuple3<E,T,K>原理類似Tuple2,類似的可以做針對4個以及更多的對象容器,作為方法返回參數類型。
