当前位置: 代码迷 >> 综合 >> Java方法返回多个对象
  详细解决方案

Java方法返回多个对象

热度:9   发布时间:2023-09-30 18:02:30.0

        在我们敲代码写方法函数的时候,可能会遇到要返回两个值,而且这两个值都有用到,所以我们一般都会用map集合进行key-value封装,或者写一个类来封装两个属性来返回,这两种方式虽然实现起来简单,但是感觉有点浪费类或者不美观,如果大量的出现这种,就大量创建类或者map集合。原因是Java 的方法函数对于多个返回参数的选项是有限制的,一种方法只能返回一个对象,数组或原始函数,而且和其他语言不同的是它也不会提供一种简易方式来消耗方法调用中的参数。

于是我们选择返回一个对象数组,一个集合,仅为返回的参数创建一个类,或者最终将其发送到你打算替换的对象中。然而这些方法都存在缺陷:

使用对象数组

        如果我们能够幸运地获取一套同类的返回参数,那么对象的数组就会是一个带有例外的选项,当我们打开这些对象时需要能分辨出每个参数。从另一方面来说,如果我们正在返回多个参数的不同类型,我们需要使用所有超类对象的数组--最有可能的就是对象本身。然后我们要抛出每一个打开的参数。我们已经丢失了类型安全性且返回参数命令出错的机会也可能增加。

使用集合

        与使用数组的方法类似,我们或许也能创造一个集合来实现返回。在集合之上使用数组主要是因为创建集合所需要代码的数量要比这段代码短:

List< Object> retVal = new ArrayList< Object>();   
retVal.add(string1);   
retVal.add(num2);   
retVal.add(object3);   
return retVal;

而创建集合的代码要高于使用数组初始化设置:

return new Object[] {string1, num2, object3}

事实上在数组之上使用集合没有什么真正的优势,除非我们要使用映射以便通过名称或其他要素来返回值。

  首次创建Java时,其简单程度是对日趋复杂的c++的一种颠覆。指针和内存管理被简化了,包括去除参数间接,常量,函数指针以及其他功能强大但容易混淆的性能。在c++中,我们可以用值或参照传递参数,这样可以对方法中的参照进行重新分配,并为你提供参数或返回更多值的方式。

使用JavaBeans

  C++也支持的structs允许简单结构化的数据包。当然,Java类可以简单完成双倍于structs的任务,但通常习惯以大量模板来扩大源码。

  使用类和JavaBeans惯例的时候还存在一个问题,即对象本质上是易变的。这些对象有可能被方法的调用者和方法调用的类共享,这样就会导致易变状态的共享,而这中情况无益于多线程系统。

  在Java中,你能用值传递的只剩下方法参数了,而且还不能是outparams,同时方法只能返回一个参数。看一下任意代码库就会发现大量的实例,不过却不是十分有效。

改进Java Beans方式

  那么应该怎样做呢?Java类选项事实上才是解决方案的关键以及对其方式进行改进。这些类可以成为structs更好的替代物。

让我们为返回的类确定两个参数:名称和出生日期: 

public class PersonNameDOB {   private String name;   private Date dob;   public Date getDob() {   return dob;   }   public void setDob(Date dob) {   this.dob = dob;   }   public String getName() {   return name;   }   public void setName(String name) {   this.name = name;   }   
}

  显然这是一个人为的例子,我们有机会拥有一个已经定义的Person类。大家肯定也会有类似的例子,需要从方法中返回两个不同的对象,但是却没有已经为其定义的类,或者是返回的类夹带多余的信息,或许是比这更糟的情况。例如,如果有人调用了你的方法来使用或修改返回对象中的值。

上述情况所需代码更多。因此我们可以做一些简单的修改:

 public class PersonNameDOB {   public final String name;   public final Date dob;   public PersonNameDOB(String name, Date dob) {   this.name = name;   this.dob = dob;   }   }

  其结果要短一些且更适合这项任务。值已经返回了,因此不需要setters了,我们只要在返回对象建成后创建值就可以了。它们不需要更改,由于它们位于构造器中,因此具有决定性作用。现在任务已经完成,将类的属性设为公开也没有风险了。同理,可以处理getters了,其结果更短,更易于使用。

偶然了解了一个知识 java里有Pair 类 正好可以解决我的这个疑惑,

Java中提供的Pair很简单,在javafx.util包下

package javafx.util;import java.io.Serializable;
import javafx.beans.NamedArg;public class Pair<K,V> implements Serializable{private K key;public K getKey() { return key; }private V value;public V getValue() { return value; }//构造方法public Pair(@NamedArg("key") K key, @NamedArg("value") V value) {this.key = key;this.value = value;}

如何使用:

Pair<String, String> pair = new Pair<>("li", "二号");
String key = pair.getKey();
String value = pair.getValue();

Apache 的 Pair 类和 Triple 类 Pair 类支持返回 2 个对象, Triple 类支持返回 3 个对象 。

org.apache.commons.lang3.tuple 包下的 Pair ,提供了 MutablePair (可变)ImmutablePair(不可变)两个子类

package org.apache.commons.lang3.tuple;import java.io.Serializable;
import java.util.Map;
import java.util.Objects;import org.apache.commons.lang3.builder.CompareToBuilder;public abstract class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {private static final class PairAdapter<L, R> extends Pair<L, R> {private static final long serialVersionUID = 1L;@Overridepublic L getLeft() {return null;}@Overridepublic R getRight() {return null;}@Overridepublic R setValue(final R value) {return null;}}private static final long serialVersionUID = 4954918890077093841L;public static final Pair<?, ?>[] EMPTY_ARRAY = new PairAdapter[0];@SuppressWarnings("unchecked")public static <L, R> Pair<L, R>[] emptyArray() {return (Pair<L, R>[]) EMPTY_ARRAY;}public static <L, R> Pair<L, R> of(final L left, final R right) {return ImmutablePair.of(left, right);}public static <L, R> Pair<L, R> of(final Map.Entry<L, R> pair) {return ImmutablePair.of(pair);}@Overridepublic int compareTo(final Pair<L, R> other) {return new CompareToBuilder().append(getLeft(), other.getLeft()).append(getRight(), other.getRight()).toComparison();}@Overridepublic final L getKey() {return getLeft();}public abstract L getLeft();public abstract R getRight();@Overridepublic R getValue() {return getRight();}public String toString(final String format) {return String.format(format, getLeft(), getRight());}}
Pair<String, String> pair = Pair.of("3", "三号");
//方式一 : getKey getValue
String key = pair.getKey();
String value = pair.getValue();
//方式二: getLeft  getRight
String left = pair.getLeft());
String right =  pair.getRight());

org.apache.commons.lang3.tuple 包中提供了针对构建三个元素的Triple类,类定义中abstract class Triple<L, M, R>。定义了3个泛型同样提供了ImmutableTripleMutableTriple一对不可变和可变的实现类

package org.apache.commons.lang3.tuple;
import java.io.Serializable;
import java.util.Objects;import org.apache.commons.lang3.builder.CompareToBuilder;public abstract class Triple<L, M, R> implements Comparable<Triple<L, M, R>>, Serializable {/** Serialization version */private static final long serialVersionUID = 1L;/*** 静态方法,返回不可变的存储三个元素的组件对象*/public static <L, M, R> Triple<L, M, R> of(final L left, final M middle, final R right) {return new ImmutableTriple<>(left, middle, right);}/*** 获取 左元素*/public abstract L getLeft();/*** 获取中元素*/public abstract M getMiddle();/*** 获取右元素*/public abstract R getRight();/*** 比较组件中三个元素的值大小*/@Overridepublic int compareTo(final Triple<L, M, R> other) {return new CompareToBuilder().append(getLeft(), other.getLeft()).append(getMiddle(), other.getMiddle()).append(getRight(), other.getRight()).toComparison();}/*** 比较三个组件中三个对象值是否相等*/@Overridepublic boolean equals(final Object obj) {if (obj == this) {return true;}if (obj instanceof Triple<?, ?, ?>) {final Triple<?, ?, ?> other = (Triple<?, ?, ?>) obj;return Objects.equals(getLeft(), other.getLeft())&& Objects.equals(getMiddle(), other.getMiddle())&& Objects.equals(getRight(), other.getRight());}return false;}/*** 返回组件对象的哈希吗*/@Overridepublic int hashCode() {return (getLeft() == null ? 0 : getLeft().hashCode()) ^(getMiddle() == null ? 0 : getMiddle().hashCode()) ^(getRight() == null ? 0 : getRight().hashCode());}/*** 打印组件的三个对象*/@Overridepublic String toString() {return "(" + getLeft() + "," + getMiddle() + "," + getRight() + ")";}/*** 格式化三个组件的对象*/public String toString(final String format) {return String.format(format, getLeft(), getMiddle(), getRight());}}

那么问题来了 如果4个范参,5个范参呢,那不好好意思,你只能通过定义bean封装返回,或者map集合返回。

你知道的越多,你不知道的越多!