没有全局变量的多次返回

时间:2014-03-11 23:22:20

标签: java oop return

在我的编程教育中可能缺少这个理论,但在面向对象的语言中,是否有可能构建一个能够return两个或更多个变量而不是一个变量的方法。

E.g。我非常喜欢Matlab处理此问题的方法:[var1, var2] = myFunction(input);

如果我只需要var1,我可以这样做:

[var1, ~] = myFunction(input);

因此丢弃我不需要的变量(在该特定情况下)。

由于我实际实现中的大量数据转换,我不想全局存储返回变量,只是一遍又一遍地调用相同的函数,但是接收该实例的指定(所需)值。

我想到了以下方法,但我想知道是否有更好的方法。

public static Double myFunction(Double input, Integer method)
{
    double calcOne   = input*5;
    double calcTwo   = input*25;
    double calcThree = input*300;

    switch(method)
    {
      case 1:  return calcOne;

      case 2:  return calcTwo;

      case 3:  return calcThree;

      default: return calcOne;
    } 
}

请注意,我显然需要return语句和计算之间的分离(实际程序中的计算涉及大for loop和读取文件等。)

修改

我之所以不使用3种不同的方法,是因为我在方法中使用了非常大的for loop。我的主要方法有时需要一个return变量来自这个方法,有时需要两个。

因此,以下可能是一个(更好的)解决方案:

public static ArrayList<Double> myFunction(double input, int[] method)
{
    double calcOne   = input*5;
    double calcTwo   = input*25;

    ArrayList<Double> returnValues = new ArrayList<Double>();

    if (Arrays.asList(method).contains(1))
    {
        returnValues.add(calcOne);
    }
    if (Arrays.asList(method).contains(2))
    {
        returnValues.add(calcTwo);
    }

    return returnValues;
}

其中int[] method包含变量&#39;名称&#39;该函数应该返回。

6 个答案:

答案 0 :(得分:2)

据我所知,不可能在一个return语句中返回多个变量。 但是,您可以定义一个调用:

public ClassA {
      public String var1;
      public int var2;
      public char var3;
      public Long var4;
}

然后填充对象并返回它。在对象内部,您可以根据需要存储尽可能多的变量,并通过一个对象返回所有变量。

答案 1 :(得分:2)

是的,这是可能的。排序。

在Java中,您可以通过返回一个对象数组,或者通过创建并返回一个轻量级类的实例来实现它,该类具有保存要返回的多个值的字段。然后调用者必须从数组或对象中提取值。

在其他OO(和非OO)语言中,有更多的直接支持;例如在某些语言(Python,Ruby,Perl等)中,您可以执行以下操作:

  [a, b, c] = someMethodReturningATuple()

LHS上的语法将值分配给变量abc

Java不支持这一点,但部分原因是它没有内置的元组类型或“任何类型的数组”类型。如果没有其中任何一个,就很难将这种语言用于语言。 (并且假设的“任何类型的数组”类型可能不会削减,因为这将依赖于调用者端的动态类型。)


请注意,这与OO与非OO无关,甚至与静态类型与动态类型语言无关。 (我在1980年代首次使用Mesa语言进行多重回归.Mesa是静态类型的。)它更多地与语言设计者认为需要支持的语言特征集相关。

答案 2 :(得分:2)

在Java中,return函数只能返回一个Object。返回多个值的备用方法(除全局变量外)如下:

  1. 使用数组

    Object [] myarray = new Object [length];
    
  2. 由于Object是您可能想要存储的大多数变量的超类,因此对象数组可以是返回多个值并仅使用您需要的值的好方法。

    使用此数组的一个缺点是它存储对象而不是更具体的数据类型(例如String),它具有自己的特殊操作集。这需要进行类型转换或其他转换才能使用特定的String操作。

    如果所有返回值都是相同的数据类型,则创建该单一数据类型的数组并避免此限制要容易得多:

      String [] mystrings = new String [length];
    
    1. 使用List
    2. 此选项与数组非常相似,但列表具有一些额外的灵活性。列表创建如下:

        List<Object> mylist = new LinkedList<Object>();
      

      添加如下项目:

        mylist.add(myVar);
      

      与数组类似,如果所有数据值都属于同一类型,则此方法可避免上述限制。

      1. 创建对象
      2. 您可以声明具有多个参数的类。这些参数具有特定的数据类型,因此它们可以将所有内置Java库用于其数据类型,而无需进行类型转换或转换。这避免了ArrayList对象的主要缺点。

            public ReturnObject () {
                 public int param1;
                 public String myString;
            }
        

        由于所有这些选项都有效,因为它们返回单个Object,但在该对象中返回了几个数据值。

答案 3 :(得分:2)

我一直在使用一种非常基本的方法来处理多重回报的问题。它有助于实现目的,并避免复杂性。

我称之为字符串分隔符方法

它有效,因为它甚至可以返回多种类型的值,例如int,double,char,string等

在这种方法中,我们使用一般不太可能发生的字符串。 我们将其称为分隔符。 当在函数

中使用时,此分隔符将用于分隔各种值

例如,我们将最终返回为(例如)intValue separator doubleValue separator ... 然后使用这个字符串,我们将检索所需的所有信息,也可以是不同的类型

以下代码将显示此概念的工作原理

使用的分隔符是!@#和  返回3个值intVal,doubleVal和stringVal

        public class TestMultipleReturns {

            public static String multipleVals() {

                String result = "";
                String separator = "!@#";


                int intVal = 5;
                // Code to process intVal

                double doubleVal = 3.14;
                // Code to process doubleVal

                String stringVal = "hello";
                // Code to process Int intVal

                result = intVal + separator + doubleVal + separator + stringVal + separator;
                return (result);
            }

            public static void main(String[] args) {

                String res = multipleVals();

                int intVal = Integer.parseInt(res.split("!@#")[0]);
                // Code to process intVal

                double doubleVal = Double.parseDouble(res.split("!@#")[1]);
                // Code to process doubleVal

                String stringVal = res.split("!@#")[2];

                System.out.println(intVal+"\n"+doubleVal+"\n"+stringVal);
            }
        }

输出

5
3.14
hello
BUILD SUCCESSFUL (total time: 2 seconds)

答案 4 :(得分:1)

E.g. I really like Matlab's way of handling this: [var1, var2] = myFunction(input);

请永远不要考虑&#34; Matlab&#34;编程语言:P

您正在寻找的等价物将是:

List<Double> result = doSomething(5);
System.out.println(result.get(0)); // 25

public List<Double> doStomething(Integer input){
   List<Double> result= new LinkedList<Double>();

   Double calcOne = input*5;
   Double calcTwo = input*25;

   result.add(calcOne);
   result.add(calcTwo);
   return result;
}

然而,即使您只是想使用&#34;所有值都是计算的,第一个结果&#34;。如果您只需要一个结果 - 创建3个方法并调用,您需要的内容,如:

public Double calcOne(Integer input){
   ...
}

public Double calcTwo(Integer input){
   ...
}

public Double calcThree(Integer input){
   ...
}

答案 5 :(得分:1)

另一个想法是创建一个使用&#34; hashmap&#34;的类。用于存储参数值的类型。这个类公开方法,例如添加参数和值,查找参数值,删除参数,获取参数个数等。重要的是隐藏使用数据类型来存储信息。如果您想要更改&#34; hashmap&#34;通过其他方式输入,当您不更改班级的公共界面时,班级的客户不会受到影响

为例

public class Context {

private HashMap<String, Object> attributes = new HashMap<String, Object>();

// Get value for parameter name
public Object getAttribute(String name) {
    return attributes.get(name);
}

// Set value for parameter name
public void setAttributes(String name, Object value) {
    removeAttributes(name);
    attributes.put(name, value);
}

// Returns the number of values 
public int getSize() {
    return this.attributes.size();
}

// remove parameter
public void removeAttributes(String name) {
    Iterator<Map.Entry<String, Object>> iter = this.attributes.entrySet().iterator();
    while (iter.hasNext()) {
        Map.Entry<String, Object> entry = iter.next();
        if (name.equalsIgnoreCase(entry.getKey())) {
            iter.remove();
            }
        }
    }
} 

此解决方案的缺点是您必须转换(强制转换)对象以获取原始值。如果你只有一种类型的数据也不是那么糟糕。通过利弊,如果你想存储几种不同的类型,它可能会变得复杂。但是,这是一个想法!!!!

@Test
public void testContext() {

    // Le context
    Context context = new Context();

    Integer param1 = new Integer(1);
    BigDecimal param2 = new BigDecimal(19700101);
    String param3 = new String("hello world");

    // Add 3 parameters (key, value)
    context.setAttributes("param_1", param1);
    context.setAttributes("param_2", param2);
    context.setAttributes("param_3", param3);
    Assert.assertEquals(3, context.getSize()); // test the number of key-value mappings in this map.

    Integer resultParam1 = (Integer) context.getAttribute("param_1");
    BigDecimal resultParam2 = (BigDecimal) context.getAttribute("param_2");
    String resultParam3 = (String) context.getAttribute("param_3");

    Assert.assertEquals(param1, resultParam1);
    Assert.assertEquals(param2, resultParam2);  
    Assert.assertEquals(param3, resultParam3);  

    // remove parameter
    context.removeAttributes("param_1");
    Assert.assertEquals(2, context.getSize());  // 3add - 1remove = 2 parameters

    // Replace value parameter by another value
    Long value = new Long(1976);
    context.setAttributes("param_2", value);

    // and so on ...
}