問(wèn)題
有時(shí)候我們調(diào)用方法的時(shí)候返回值有可能不止1個(gè),比如說(shuō)我們返回name = "張三" age = 20
這兩個(gè)值咧虎,那么這個(gè)時(shí)候方法的返回值怎么寫(xiě)呢庸疾。在Scala和python中都有Tuple使用,在java中我們?cè)趺崔k睡互。很容易我們就想到了一個(gè)方式:可以構(gòu)造一個(gè)User類來(lái)封裝這兩個(gè)屬性肠套。
但是如果返回的兩個(gè)值并沒(méi)有任何關(guān)聯(lián)關(guān)系舰涌,或者說(shuō)每一個(gè)方法返回的參數(shù)都不同,那么我們就得為每一個(gè)方法的返回類型去創(chuàng)建對(duì)應(yīng)的類來(lái)取包裝你稚,或許還有其他的解決方式瓷耙,比如說(shuō)返回一個(gè)map,返回一個(gè)List刁赖,返回一個(gè)array都可以搁痛。
使用map作為返回值的話調(diào)用方在不清楚map中具體有什么內(nèi)容的時(shí)候需要去遍歷keySet或entrySet,而list和array也是同樣的問(wèn)題,不知道哪一個(gè)參數(shù)存放在哪里宇弛。
解決方式
其實(shí)前人已經(jīng)為我們解決了這個(gè)問(wèn)題鸡典。
如果你經(jīng)常使用apache的commons-lang3包來(lái)處理String的null判斷,那么你依舊可以從這個(gè)包中找到我們想要的一個(gè)所謂的元組枪芒。
org.apache.commons.lang3.tuple.Pair
/**
* <p>A pair consisting of two elements.</p>
*
* <p>This class is an abstract implementation defining the basic API.
* It refers to the elements as 'left' and 'right'. It also implements the
* {@code Map.Entry} interface where the key is 'left' and the value is 'right'.</p>
*
* <p>Subclass implementations may be mutable or immutable.
* However, there is no restriction on the type of the stored objects that may be stored.
* If mutable objects are stored in the pair, then the pair itself effectively becomes mutable.</p>
*
* @param <L> the left element type
* @param <R> the right element type
*
* @since Lang 3.0
*/
public abstract class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {
/** Serialization version */
private static final long serialVersionUID = 4954918890077093841L;
/**
* <p>Obtains an immutable pair of from two objects inferring the generic types.</p>
*
* <p>This factory allows the pair to be created using inference to
* obtain the generic types.</p>
*
* @param <L> the left element type
* @param <R> the right element type
* @param left the left element, may be null
* @param right the right element, may be null
* @return a pair formed from the two parameters, not null
*/
public static <L, R> Pair<L, R> of(final L left, final R right) {
return new ImmutablePair<>(left, right);
}
//-----------------------------------------------------------------------
/**
* <p>Gets the left element from this pair.</p>
*
* <p>When treated as a key-value pair, this is the key.</p>
*
* @return the left element, may be null
*/
public abstract L getLeft();
/**
* <p>Gets the right element from this pair.</p>
*
* <p>When treated as a key-value pair, this is the value.</p>
*
* @return the right element, may be null
*/
public abstract R getRight();
/**
* <p>Gets the key from this pair.</p>
*
* <p>This method implements the {@code Map.Entry} interface returning the
* left element as the key.</p>
*
* @return the left element as the key, may be null
*/
@Override
public final L getKey() {
return getLeft();
}
/**
* <p>Gets the value from this pair.</p>
*
* <p>This method implements the {@code Map.Entry} interface returning the
* right element as the value.</p>
*
* @return the right element as the value, may be null
*/
@Override
public R getValue() {
return getRight();
}
//-----------------------------------------------------------------------
/**
* <p>Compares the pair based on the left element followed by the right element.
* The types must be {@code Comparable}.</p>
*
* @param other the other pair, not null
* @return negative if this is less, zero if equal, positive if greater
*/
@Override
public int compareTo(final Pair<L, R> other) {
return new CompareToBuilder().append(getLeft(), other.getLeft())
.append(getRight(), other.getRight()).toComparison();
}
/**
* <p>Compares this pair to another based on the two elements.</p>
*
* @param obj the object to compare to, null returns false
* @return true if the elements of the pair are equal
*/
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Map.Entry<?, ?>) {
final Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
return Objects.equals(getKey(), other.getKey())
&& Objects.equals(getValue(), other.getValue());
}
return false;
}
/**
* <p>Returns a suitable hash code.
* The hash code follows the definition in {@code Map.Entry}.</p>
*
* @return the hash code
*/
@Override
public int hashCode() {
// see Map.Entry API specification
return (getKey() == null ? 0 : getKey().hashCode()) ^
(getValue() == null ? 0 : getValue().hashCode());
}
/**
* <p>Returns a String representation of this pair using the format {@code ($left,$right)}.</p>
*
* @return a string describing this object, not null
*/
@Override
public String toString() {
return new StringBuilder().append('(').append(getLeft()).append(',').append(getRight()).append(')').toString();
}
/**
* <p>Formats the receiver using the given format.</p>
*
* <p>This uses {@link java.util.Formattable} to perform the formatting. Two variables may
* be used to embed the left and right elements. Use {@code %1$s} for the left
* element (key) and {@code %2$s} for the right element (value).
* The default format used by {@code toString()} is {@code (%1$s,%2$s)}.</p>
*
* @param format the format string, optionally containing {@code %1$s} and {@code %2$s}, not null
* @return the formatted string, not null
*/
public String toString(final String format) {
return String.format(format, getLeft(), getRight());
}
}
這個(gè)類構(gòu)建了一個(gè)由兩個(gè)元素組成的一個(gè)元組彻况,left
和right
兩個(gè)元素谁尸。
繼承了Map.Entry,可以使用getKey()
和getValue()
方法疗垛,從源碼中我們也發(fā)現(xiàn)其實(shí)是調(diào)用了他本身的getLeft()
和getRight()
方法,而這兩個(gè)方法是需要子類去實(shí)現(xiàn)硫朦,我們后面說(shuō)贷腕。
繼承了Comparable,可以比較兩個(gè)Pair咬展。
繼承了Serializable泽裳,可以被序列化。
比較重要的就是getKey()
和getValue()
破婆,下面我們看這個(gè)類的兩個(gè)實(shí)現(xiàn)ImmutablePair
和MutablePair
涮总。
ImmutablePair
很好理解,不可變的Pair祷舀,相對(duì)的MutablePair
就是可變的Pair
先看ImmutablePair.class
/**
* <p>An immutable pair consisting of two {@code Object} elements.</p>
*
* <p>Although the implementation is immutable, there is no restriction on the objects
* that may be stored. If mutable objects are stored in the pair, then the pair
* itself effectively becomes mutable. The class is also {@code final}, so a subclass
* can not add undesirable behaviour.</p>
*
* <p>#ThreadSafe# if both paired objects are thread-safe</p>
*
* @param <L> the left element type
* @param <R> the right element type
*
* @since Lang 3.0
*/
public final class ImmutablePair<L, R> extends Pair<L, R> {
/**
* An immutable pair of nulls.
*/
// This is not defined with generics to avoid warnings in call sites.
@SuppressWarnings("rawtypes")
private static final ImmutablePair NULL = ImmutablePair.of(null, null);
/** Serialization version */
private static final long serialVersionUID = 4954918890077093841L;
/**
* Returns an immutable pair of nulls.
*
* @param <L> the left element of this pair. Value is {@code null}.
* @param <R> the right element of this pair. Value is {@code null}.
* @return an immutable pair of nulls.
* @since 3.6
*/
@SuppressWarnings("unchecked")
public static <L, R> ImmutablePair<L, R> nullPair() {
return NULL;
}
/** Left object */
public final L left;
/** Right object */
public final R right;
/**
* <p>Obtains an immutable pair of from two objects inferring the generic types.</p>
*
* <p>This factory allows the pair to be created using inference to
* obtain the generic types.</p>
*
* @param <L> the left element type
* @param <R> the right element type
* @param left the left element, may be null
* @param right the right element, may be null
* @return a pair formed from the two parameters, not null
*/
public static <L, R> ImmutablePair<L, R> of(final L left, final R right) {
return new ImmutablePair<>(left, right);
}
/**
* Create a new pair instance.
*
* @param left the left value, may be null
* @param right the right value, may be null
*/
public ImmutablePair(final L left, final R right) {
super();
this.left = left;
this.right = right;
}
//-----------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public L getLeft() {
return left;
}
/**
* {@inheritDoc}
*/
@Override
public R getRight() {
return right;
}
/**
* <p>Throws {@code UnsupportedOperationException}.</p>
*
* <p>This pair is immutable, so this operation is not supported.</p>
*
* @param value the value to set
* @return never
* @throws UnsupportedOperationException as this operation is not supported
*/
@Override
public R setValue(final R value) {
throw new UnsupportedOperationException();
}
}
public final L left;
和public final R right;
兩個(gè)不可變的值注定了這個(gè)類是不可變的瀑梗。
在構(gòu)造方法ImmutablePair(final L left, final R right)
中初始化這兩個(gè)值。
本類實(shí)現(xiàn)了 getLeft()
和getRight()
方法裳扯,返回left
和right
抛丽。
當(dāng)我們?cè)噲D調(diào)用setValue()
方法的時(shí)候會(huì)拋出UnsupportedOperationException
異常,因?yàn)檫@一對(duì)值是不可變的饰豺。
ImmutablePair.class
public void setRight(final R right) {
this.right = right;
}
public void setLeft(final L left) {
this.left = left;
}
public R setValue(final R value) {
final R result = getRight();
setRight(value);
return result;
}
MutablePair
和ImmutablePair
類基本一樣亿鲜,只是在定義public L left;
和public R right;
沒(méi)有使用final
類型的。注定了可以修改這兩個(gè)值冤吨。并且提供了setter方法可以供修改這一對(duì)值蒿柳,并且提供了setValuef()
方法修改right
值。
現(xiàn)在我們可以愉快的使用這個(gè)類來(lái)作為返回兩個(gè)參數(shù)的方法的返回值了漩蟆。
提問(wèn)
如果你想問(wèn)垒探,我返回的參數(shù)不是2個(gè),是3個(gè)怎么辦怠李?
沒(méi)問(wèn)題叛复,一樣滿足你,在這個(gè)org.apache.commons.lang3.tuple
包中提供了針對(duì)構(gòu)建三個(gè)元素的Triple
類扔仓,類定義中abstract class Triple<L, M, R>
褐奥。定義了3個(gè)泛型同樣提供了ImmutableTriple
和MutableTriple
一對(duì)不可變和可變的實(shí)現(xiàn)類。
你過(guò)你還問(wèn)我翘簇,我返回的參數(shù)是4個(gè)怎么辦撬码,還有什么類可以供我使用嗎?
抱歉版保,或許你需要定義java bean 去實(shí)現(xiàn)你的復(fù)雜返回值:)呜笑。