Output Parameters in Java

2020-04-08 12:40发布

With a third party API I observed the following.

Instead of using,

public static string getString(){
   return "Hello World";
}

it uses something like

public static void getString(String output){

}

and I am getting the "output" string assigned.

I am curious about the reason of implementing such functionality. What are the advantages of using such output parameters?

8条回答
一纸荒年 Trace。
2楼-- · 2020-04-08 12:57

Actually, it is impossible to have out parameters in java but you can make a work around making the method take on a de-reference for the immutable String and primitives by either writing a generic class where the immutable is the generic with the value and setter and getter or by using an array where element 0 (1 in length) is the value provided it is instantiate first because there are situations where you need to return more than one value where having to write a class just to return them where the class is only used there is just a waste of text and not really re-usable.

Now being a C/C++ and also .Net (mono or MS), it urges me that java does not support at least a de-reference for primitives; so, I resort to the array instead.

Here is an example. Let's say you need to create a function (method) to check whether the index is valid in the array but you also want to return the remainding length after the index is validated. Let's call it in c as 'bool validate_index(int index, int arr_len, int&rem)'. A way to do this in java would be 'Boolean validate_index(int index, int arr_len, int[] rem1)'. rem1 just means the array hold 1 element.

public static Boolean validate_index(int index, int arr_len, int[] rem1)
{
    if (index < 0 || arr_len <= 0) return false;

    Boolean retVal = (index >= 0 && index < arr_len);

    if (retVal && rem1 != null) rem1[0] = (arr_len - (index + 1));

    return retVal;

}

Now if we use this we can get both the Boolean return and the remainder.

 public static void main(String[] args)
 {
    int[] ints = int[]{1, 2, 3, 4, 5, 6};
    int[] aRem = int[]{-1};
    //because we can only scapegoat the de-ref we need to instantiate it first.
    Boolean result = validate_index(3, ints.length, aRem);

    System.out.println("Validation = " + result.toString());
    System.out.println("Remainding elements equals " + aRem[0].toString());

 }

puts: Validation = True puts: Remainding elements equals 2

Array elements always either point to the object on the stack or the address of the object on the heap. So using it as a de-references is absolutely possible even for arrays by making it a double array instantiating it as myArrayPointer = new Class[1][] then passing it in because sometimes you don't know what the length of the array will until the call going through an algorithm like 'Boolean tryToGetArray(SomeObject o, T[][] ppArray)' which would be the same as in c/c++ as 'template bool tryToGetArray (SomeObject* p, T** ppArray)' or C# 'bool tryToGetArray(SomeObject o, ref T[] array)'. It works and it works well as long as the [][] or [] is instantiate in memory first with at least one element.

查看更多
Lonely孤独者°
3楼-- · 2020-04-08 13:06

This functionality has one big disadvantage - it doesn't work. Function parameters are local to function and assigning to them doesn't have any impact outside the function.
On the other hand

void getString(StringBuilder builder) {
    builder.delete(0, builder.length());
    builder.append("hello world");
}

will work, but I see no advantages of doing this (except when you need to return more than one value).

查看更多
爷的心禁止访问
4楼-- · 2020-04-08 13:08

in my opinion, this is useful when you have more than one result in a function.

查看更多
何必那么认真
5楼-- · 2020-04-08 13:10

String are immutable, you cannot use Java's pseudo output parameters with immutable objects.

Also, the scope of output is limited to the getString method. If you change the output variable, the caller won't see a thing.

What you can do, however, is change the state of the parameter. Consider the following example:

void handle(Request r) {
    doStuff(r.getContent());
    r.changeState("foobar");
    r.setHandled();
}

If you have a manager calling multiple handles with a single Request, you can change the state of the Request to allow further processing (by other handlers) on a modified content. The manager could also decide to stop processing.

Advantages:

  • You don't need to return a special object containing the new content and whether the processing should stop. That object would only be used once and creating the object waste memory and processing power.
  • You don't have to create another Request object and let the garbage collector get rid of the now obsolete old reference.
  • In some cases, you can't create a new object. For example, because that object was created using a factory, and you don't have access to it, or because the object had listeners and you don't know how to tell the objects that were listening to the old Request that they should instead listen to the new Request.
查看更多
Summer. ? 凉城
6楼-- · 2020-04-08 13:10

Sometimes this mechanism can avoid creation of a new object.

Example: If an appropriate object exists anyhow, it is faster to pass it to the method and get some field changed.

This is more efficient than creating a new object inside the called method, and returning and assigning its reference (producing garbage that needs to be collected sometime).

查看更多
够拽才男人
7楼-- · 2020-04-08 13:11

Something isn't right in your example.

class Foo {

    public static void main(String[] args) {
        String x = "foo";
        getString(x);
        System.out.println(x);
    }

    public static void getString(String output){
        output = "Hello World"
    }
}

In the above program, the string "foo" will be output, not "Hello World".

Some types are mutable, in which case you can modify an object passed into a function. For immutable types (such as String), you would have to build some sort of wrapper class that you can pass around instead:

class Holder<T> {
    public Holder(T value) {
        this.value = value;
    }
    public T value;
}

Then you can instead pass around the holder:

public static void main(String[] args) {
    String x = "foo";
    Holder<String> h = new Holder(x);
    getString(h);
    System.out.println(h.value);
}

public static void getString(Holder<String> output){
    output.value = "Hello World"
}
查看更多
登录 后发表回答