11

In PL/SQL (or many other languages), I can have IN OUT or OUT parameters, which are returned from a procedure. How can I achieve a similar thing in Java?

I know this trick:

public void method(String in, String[] inOut, String[] inOut2) {
  inOut[0] = in;
}

Where the in parameter represents an IN parameter and the inOut parameter can hold a return value. The convention would be that String[] inOut is an array of inOut.length == 1.

That's kind of clumsy.

EDIT Feedback to answers: Other tricks include:

  • holder/wrapper classes, but I don't want to introduce any new types, callbacks, etc.
  • return values: I'd like a general solution. I.e. one with several IN OUT parameters involved.
  • wrapper for IN OUT parameter as a return value: That's a viable option, but still not so nice, because that wrapper would have to be generated somehow

Does anyone know a better way to achieve this generally? The reason I need a general solution is because I want to generate convenience source code from PL/SQL in a database schema.

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • 1
    *"return values: I'd like a general solution. I.e. one with several IN OUT parameters involved"* See my answer. Several IN/OUT params? Return an object instance with properties for each. Barring that, no, there's nothing better than the array trick. – T.J. Crowder Dec 15 '10 at 22:52
  • 1
    When I first began learning Java, after many years of C/C++ development, I also looked for a way to pass by reference. But now, years after that, I can no longer recall the last time I wanted to do that. The array trick is less elegant than other approaches cited in these answers and comments. – Andy Thomas Dec 15 '10 at 23:05

3 Answers3

13

My question would be: Why doesn't method return something? Rather than setting an in/out argument?

But assuming you absolutely, positively must have an in/out argument, which is a whole different question, then the array trick is fine. Alternately, it's not less clumsy, but the other way is to pass in an object reference:

public class Foo {
    private String value;

    public Foo(String v) {
        this.value = v;
    }

    public String getValue() {
        return this.value;
    }

    public void setValue(String v) {
        this.value = v;
    }
 }

 // ....
 public void method(String in, Foo inOut) {
     inOut.setValue(in);
 }

(Or, of course, just make value public.) See? I said it wasn't less clumsy.

But I'd ask again: Can't method return something? And if it needs to return multiple things, can't it return an object instance with properties for those things?

Off-topic: This is one of the areas where I really like the C# approach. One of the arguments against in/out arguments is that they're unclear at the point where you're calling the function. So C# makes you make it clear, by specifying the keyword both at the declaration of the function and when calling it. In the absense of that kind of syntactic help, I'd avoid "simulating" in/out arguments.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • The method won't be able to return a single value, because I need a **general** solution. I have adapted the example to hold several IN OUT parameters. But maybe returning a generated result object (holding the IN OUT parameters) might actually be an option. +1 for that. – Lukas Eder Dec 15 '10 at 22:53
  • You're right about your off-topic comment. In general I don't need IN OUT parameters. But as I'm generating source code from actual PL/SQL code, I can't do without... :-/ – Lukas Eder Dec 15 '10 at 22:55
  • In my case I need inout because the method is already returning something else. – André Fratelli Jul 03 '16 at 23:53
4

Java copies anything you pass as an argument. If you pass a primitive, inside method you have copy of that primitive, and no modifications will affect the actual variable outside method. If you pass object, you pass copy of reference, which actually references to the original object. This is the way how you can propagate modifications to the context of something that called the method - by modifying the state of the object that the reference is 'pointing' to. See more on this: Does Java Pass by Value or by Reference?

Art Licis
  • 3,619
  • 1
  • 29
  • 49
  • Thanks, I know that Java doesn't pass actual pointers but "reference copies". That's why I came up with the array trick. That's a very common way to simulate pointers in Java... – Lukas Eder Dec 15 '10 at 22:48
  • +1 for actually explaining the pass-by-value semantics Java uses in a logical manner. There are too few people like you in today's world... – Platinum Azure Dec 15 '10 at 22:49
  • 1
    @Lukas: *I know that Java doesn't pass actual pointers but "reference copies"* Which is just another term for pointers. ;-) – T.J. Crowder Dec 15 '10 at 22:51
  • @T.J. Crowder: As far as I know in C/C++, you can assign a new value to a pointer that will be able to leave the scope of the method. In Java, this is not possible, as Arturs correctly explained. The "pointer" is passed by value to the method, not by reference – Lukas Eder Dec 15 '10 at 22:57
  • 1
    @Lukas: *"As far as I know in C/C++, you can assign a new value to a pointer that will be able to leave the scope of the method. In Java, this is not possible..."* Java's object references (`void foo(MyObject m)`) are exact analogs of C/C++ pointers (`void foo(MyObject *pm)`). You can assign to `m` (Java), or `mp` (C/C++), but that doesn't have any effect on anything outside `foo`. But C/C++ has pointers *to pointers*: `void foo(MyObject **ppm)`, where the effect of writing to `*ppm` can be seen in the calling method. Java's analog is the array trick the OP flagged up. – T.J. Crowder Dec 16 '10 at 04:05
  • @Lukas: (continuing) But granted, I'm not immediately thinking of a Java equivalent to a pointer to a pointer *to a pointer*, `void foo(MyObject ***pppm)`. :-) – T.J. Crowder Dec 16 '10 at 04:08
  • OK, that's what I meant. Thanks for the clarification – Lukas Eder Dec 16 '10 at 07:30
  • 1
    @T.J.Crowder Oh right I'm sorry. I should have read more carefully. – Marcin K. Nov 12 '21 at 14:57
2

There's no direct way. Other techniques include:

  • Passing a holder object (a bit like your 1-ary array)
  • Using, e.g., an AtomicInteger
  • Passing a more useful object from a business perspective that happens to be mutable
  • A callback to a custom interface for receiving the result

If you think about it, the array trick is not dissimilar to passing a T* in C/C++

dty
  • 18,795
  • 6
  • 56
  • 82