Question

Avec une API tierce, j'ai observé ce qui suit.

Au lieu d'utiliser,

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

il utilise quelque chose comme

public static void getString(String output){

}

et je reçois la "sortie". chaîne assignée.

Je suis curieux de savoir pourquoi cette fonctionnalité est implémentée. Quels sont les avantages de l’utilisation de tels paramètres de sortie?

Était-ce utile?

La solution

Quelque chose ne va pas dans votre exemple.

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

Dans le programme ci-dessus, la chaîne " foo " sera affiché, pas "Hello World".

Certains types sont modifiables, auquel cas vous pouvez modifier un objet passé à une fonction. Pour les types immuables (tels que String ), vous devez créer une sorte de classe wrapper que vous pouvez transmettre à la place:

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

Ensuite, vous pouvez plutôt faire passer le titulaire:

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

Autres conseils

Je ne suis pas d’accord avec Jasper: "À mon avis, c’est une très mauvaise et très mauvaise façon de renvoyer plus d’un résultat". Dans .NET, il existe une construction intéressante qui utilise les paramètres de sortie:

bool IDictionary.TryGet(key, out value);

Je le trouve très utile et élégant. Et c’est le moyen le plus pratique de demander si un élément est en collection et de le renvoyer en même temps. Avec cela, vous pouvez écrire:

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

Je gronde constamment mes développeurs si je vois du code de style ancien comme:

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

Vous voyez, cela réduit les performances de moitié. En Java, il n’existe aucun moyen de différencier la valeur null d’un élément existant de la non-existence d’un élément dans une carte en un seul appel. Parfois, cela est nécessaire.

Cet exemple est faux, Java n'a pas de paramètre de sortie.

Une chose que vous pouvez faire pour imiter ce comportement est la suivante:

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

Mais à mon humble avis, cela aspire à plusieurs niveaux. :)

Si vous voulez qu'une méthode retourne quelque chose, faites-la lui retourner. Si vous devez renvoyer plusieurs objets, créez une classe conteneur dans laquelle placer ces objets et les renvoyer.

Cette fonctionnalité a un gros inconvénient: elle ne fonctionne pas. Les paramètres de fonction sont locaux à fonction et leur affectation n'a aucun impact en dehors de la fonction.
D'autre part

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

fonctionnera, mais je ne vois aucun avantage à le faire (sauf lorsque vous devez renvoyer plusieurs valeurs).

Les chaînes sont immuables, vous ne pouvez pas utiliser les pseudo paramètres de sortie de Java avec des objets immuables.

En outre, la portée de la sortie est limitée à la méthode getString . Si vous modifiez la variable output , l'appelant ne verra rien.

Ce que vous pouvez faire, cependant, est de changer l'état du paramètre. Prenons l'exemple suivant:

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

Si un responsable appelle plusieurs descripteurs avec une seule demande, vous pouvez modifier l'état de la demande pour autoriser un traitement ultérieur (par d'autres gestionnaires) sur un contenu modifié. Le responsable peut également décider de mettre fin au traitement.

Avantages:

  • Il n'est pas nécessaire de renvoyer un objet spécial contenant le nouveau contenu ni d'indiquer si le traitement doit être interrompu. Cet objet ne serait utilisé qu'une seule fois et créerait une perte de mémoire et de puissance de traitement.
  • Vous n'avez pas besoin de créer un autre objet Request et de laisser le ramasse-miettes se débarrasser de l'ancienne référence désormais obsolète.
  • Dans certains cas, vous ne pouvez pas créer un nouvel objet. Par exemple, parce que cet objet a été créé à l'aide d'une fabrique et que vous n'y avez pas accès, ou parce qu'il avait des écouteurs et que vous ne savez pas comment indiquer aux objets qui écoutaient l'ancienne requête qu'ils devraient plutôt écoutez la nouvelle demande.

En fait, il est impossible d’avoir des paramètres en java, mais vous pouvez contourner le problème en faisant en sorte que la méthode prenne un renvoi à la chaîne immuable et aux primitives en écrivant une classe générique où immuable est le générique avec valeur et setter et getter ou en utilisant un tableau où l'élément 0 (1 en longueur) est la valeur à condition qu'il soit instancié en premier, car il existe des situations dans lesquelles vous devez renvoyer plusieurs valeurs, ce qui vous oblige à écrire une classe simplement pour les renvoyer où la classe est seulement utilisée il y a juste un gaspillage de texte et pas vraiment réutilisable.

Etant à présent en C / C ++ et également en .Net (mono ou MS), j’insiste sur le fait que java ne prend pas en charge au moins un renvoi aux primitives; alors, je recourt au tableau à la place.

Voici un exemple. Supposons que vous deviez créer une fonction (méthode) pour vérifier si l'index est valide dans le tableau, mais vous souhaitez également renvoyer la longueur restante une fois l'index validé. Appelons-le dans c comme 'bool validate_index (int index, int arr_len, int & rem)'. Un moyen de faire cela en Java serait 'Boolean validate_index (int index, int arr_len, int [] rem1)'. rem1 signifie simplement que le tableau contient 1 élément.

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;

}

Maintenant, si nous l'utilisons, nous pouvons obtenir le retour booléen et le reste.

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

 }

met: Validation = True met: Les éléments restants sont égaux à 2

Les éléments de tableau pointent toujours sur l'objet de la pile ou sur l'adresse de l'objet sur le tas. Il est donc tout à fait possible de l'utiliser en tant que référence, même pour les tableaux, en créant un double tableau l'instanciant sous la forme myArrayPointer = new Class [1] [], puis en le passant, car vous ne savez parfois pas quelle sera la longueur du tableau. jusqu'à ce que l'appel passe par un algorithme tel que 'Boolean tryToGetArray (SomeObject o, T [] [] ppArray)' qui serait identique à celui de c / c ++ en tant que 'template bool tryToGetArray (SomeObject * p, T ** ppArray)' ou C # 'bool tryToGetArray (SomeObject o, ref T [] array)'. Cela fonctionne bien tant que le [] [] ou le [] est instancié en mémoire d’abord avec au moins un élément.

Parfois, ce mécanisme peut éviter la création d'un nouvel objet.

Exemple: Si un objet approprié existe de toute façon, il est plus rapide de le passer à la méthode et de faire modifier un champ.

Cela est plus efficace que de créer un nouvel objet dans la méthode appelée, et de renvoyer et d'affecter sa référence (production de déchets qui doivent être collectés à un moment donné).

à mon avis, cela est utile lorsque vous avez plusieurs résultats dans une fonction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top