Java 中的输出参数

发布于 2024-08-04 12:43:48 字数 282 浏览 3 评论 0原文

通过第三方 API,我观察到以下情况。

它没有使用,而是

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

使用类似的东西

public static void getString(String output){

}

,我正在分配“输出”字符串。

我很好奇实现这样的功能的原因。使用这样的输出参数有什么优点?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

海螺姑娘 2024-08-11 12:43:49

你的例子中有些地方不对劲。

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"
    }
}

在上面的程序中,将输出字符串“foo”,而不是“Hello World”。

有些类型是可变的,在这种情况下,您可以修改传递给函数的对象。对于不可变类型(例如String),您必须构建某种可以传递的包装类:然后

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

您可以传递持有者:

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"
}

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"
}
无力看清 2024-08-11 12:43:49

那个例子是错误的,Java没有输出参数。

你可以做的一件事是模仿这种行为:

public void doSomething(String[] output) {
    output[0] = "Hello World!";
}

但恕我直言,这在多个层面上都很糟糕。 :)

如果你想要一个方法返回一些东西,就让它返回它。如果需要返回多个对象,请创建一个容器类来放入这些对象并返回该对象。

That example is wrong, Java does not have output parameters.

One thing you could do to emulate this behaviour is:

public void doSomething(String[] output) {
    output[0] = "Hello World!";
}

But IMHO this sucks on multiple levels. :)

If you want a method to return something, make it return it. If you need to return multiple objects, create a container class to put these objects into and return that.

酒中人 2024-08-11 12:43:49

我不同意 Jesper 的 评论:“在我看来,这真的很丑陋一种返回多个结果的糟糕方法”。
在 .NET 中,有一个利用输出参数的有趣构造:

bool IDictionary.TryGet(key, out value);

我发现它非常有用且优雅。这是询问某个项目是否在集合中并同时返回它的最方便的方法。有了它,你可以写:

object obj;
if (myList.TryGet(theKey, out obj))
{
  ... work with the obj;
}

如果我看到旧式代码,我会不断责骂我的开发人员,例如:

if (myList.Contains(theKey))
{
  obj = myList.Get(theKey);
}

你看,它会将性能降低一半。在 Java 中,无法在一次调用中区分 Map 中现有项的 null 值与不存在项。有时这是必要的。

I disagree with Jesper's comment: "In my opinion, this is a really ugly and bad way to return more than one result".
In .NET there is a interesting construct that utilize the output parameters:

bool IDictionary.TryGet(key, out value);

I find it very usefull and elegant. And it is the most convenient way to aks if an item is in collection and return it at the same time. With it you may write:

object obj;
if (myList.TryGet(theKey, out obj))
{
  ... work with the obj;
}

I constantly scold my developers if I see old-style code like:

if (myList.Contains(theKey))
{
  obj = myList.Get(theKey);
}

You see, it cuts the performance in half. In Java there is no way to differentiate null value of an existing item from non-existance of an item in a Map in one call. Sometimes this is necessary.

莫多说 2024-08-11 12:43:49

这个功能有一个很大的缺点——它不起作用。函数参数是函数的本地参数,对它们进行赋值不会对函数外部产生任何影响。
另一方面

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

会起作用,但我认为这样做没有任何优势(除非您需要返回多个值)。

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).

海夕 2024-08-11 12:43:49

有时这种机制可以避免创建新对象。

例子:
无论如何,如果存在适当的对象,则将其传递给方法并更改某些字段会更快。

这比在被调用方法内创建新对象并返回并分配其引用(产生有时需要收集的垃圾)更有效。

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).

白况 2024-08-11 12:43:49

字符串是不可变的,不能将 Java 的伪输出参数与不可变对象一起使用。

此外,输出的范围仅限于getString方法。如果您更改输出变量,调用者将看不到任何东西。

但是,您可以做的是更改参数的状态。请考虑以下示例:

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

如果您有一个管理器使用单个请求调用多个句柄,则您可以更改请求的状态以允许对修改的内容进行进一步处理(由其他处理程序)。经理也可以决定停止处理。

优点:

  • 您不需要返回包含新内容以及处理是否应该停止的特殊对象。该对象只能使用一次,创建该对象会浪费内存和处理能力。
  • 您不必创建另一个 Request 对象并让垃圾收集器删除现在已过时的旧引用。
  • 在某些情况下,您无法创建新对象。例如,因为该对象是使用工厂创建的,并且您无权访问它,或者因为该对象具有侦听器,并且您不知道如何告诉正在侦听旧请求的对象,他们应该改为听取新的请求。

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.
春夜浅 2024-08-11 12:43:49

实际上,在 java 中不可能有 out 参数,但您可以通过编写一个泛型类(其中不可变是具有值和 setter 的泛型)来解决方法,使该方法对不可变 String 和基元进行取消引用和 getter 或使用一个数组,其中元素 0(长度为 1)是它首先实例化的值,因为在某些情况下,您需要返回多个值,而必须编写一个类才能将它们返回到类所在的位置仅在那里使用只是浪费文本并且不能真正重复使用。

现在作为一个 C/C++ 和 .Net(mono 或 MS),它敦促我 java 至少不支持对原语的取消引用;所以,我改用数组。

这是一个例子。假设您需要创建一个函数(方法)来检查数组中的索引是否有效,但您还希望在索引验证后返回剩余长度。我们在 c 中将其称为“bool validate_index(int index, int arr_len, int&rem)”。在 java 中执行此操作的一种方法是“Boolean validate_index(int index, int arr_len, int[] rem1)”。 rem1 只是表示数组包含 1 个元素。

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;

}

现在,如果我们使用它,我们可以获得布尔返回值和余数。

 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());

 }

投入:验证= True
put:剩余元素等于 2

数组元素始终要么指向堆栈上的对象,要么指向堆上对象的地址。因此,即使对于数组,也可以将其用作取消引用,方法是使其成为双数组,将其实例化为 myArrayPointer = new Class[1][],然后将其传入,因为有时您不知道数组的长度是多少直到调用通过类似“Boolean tryToGetArray(SomeObject o, T[][] ppArray)”的算法,该算法与 c/c++ 中的“template bool tryToGetArray (SomeObject* p, T** ppArray)”相同,或者C# 'bool tryToGetArray(SomeObject o, ref T[] array)'。
只要 [][] 或 [] 首先使用至少一个元素在内存中实例化,它就可以正常工作。

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.

面如桃花 2024-08-11 12:43:49

在我看来,当函数中有多个结果时,这很有用。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文