Fonctions imbriquées en Java

y a-t-il des extensions pour le langage de programmation Java qui permettent de créer des fonctions imbriquées? Il y a de nombreuses situations où je dois créer des méthodes qui ne sont utilisées qu'une seule fois dans le contexte d'une autre méthode ou pour-boucle. J'ai été incapable de l'accomplir en Java jusqu'à présent, même si cela peut être fait facilement en Javascript.

par exemple, cela ne peut pas être fait en Java standard:

for(int i = 1; i < 100; i++){
    times(2); //multiply i by 2 and print i
    times(i); //square i and then print the result
    public void times(int num){

        i *= num;
        System.out.println(i);
    }    
}
39
demandé sur Matt Ball 2011-09-10 01:36:53

6 réponses

Java 8 présente lambdas.

java.util.function.BiConsumer<Integer, Integer> times = (i, num) -> {
    i *= num;
    System.out.println(i);
};
for (int i = 1; i < 100; i++) {
    times.accept(i, 2); //multiply i by 2 and print i
    times.accept(i, i); //square i and then print the result
}

la syntaxe () -> fonctionne sur n'importe quelle interface qui définit exactement une méthode. Donc vous pouvez l'utiliser avec Runnable mais il ne fonctionne pas avec List .

BiConsumer est l'une des nombreuses interfaces fonctionnelles fournies par java.util.la fonction .

il est intéressant de noter que sous le capot, cela définit une classe anonyme et l'instancie. times est une référence à l'instance.

37
répondu Neal Ehardt 2015-02-18 05:27:26

la réponse ci-dessous est de parler de la plus proche que vous pouvez obtenir d'avoir des fonctions imbriquées en Java avant Java 8. Ce n'est pas nécessairement la façon dont je m'occuperais des mêmes tâches qui pourraient être traitées avec des fonctions imbriquées dans Javascript. Souvent, une méthode d'aide privée fera tout aussi bien - peut-être même un helper privé type , dont vous créez une instance de dans la méthode, mais qui est disponible pour toutes les méthodes.

en Java 8 Bien sûr, il sont des expressions lambda qui sont une solution beaucoup plus simple.


le plus proche que vous pouvez facilement venir est avec une classe interne anonyme. C'est aussi proche que Java en vient aux fermetures pour le moment, bien que j'espère qu'il y aura plus de support dans Java 8.

les classes intérieures anonymes ont diverses limitations - elles sont évidemment assez verbeuses par rapport à votre exemple Javascript (ou n'importe quoi utilisant lambdas) et leur accès à l'enveloppe l'environnement est limité aux variables finales.

pour (horriblement) pervertir votre exemple:

interface Foo {
    void bar(int x);
}

public class Test {
    public static void main(String[] args) {
        // Hack to give us a mutable variable we can
        // change from the closure.
        final int[] mutableWrapper = { 0 };

        Foo times = new Foo() {
            @Override public void bar(int num) {
                mutableWrapper[0] *= num;
                System.out.println(mutableWrapper[0]);
            }
        };

        for (int i = 1; i < 100; i++) {
            mutableWrapper[0] = i;
            times.bar(2);
            i = mutableWrapper[0];

            times.bar(i);
            i = mutableWrapper[0];
        }
    }
}

sortie:

2
4
10
100

est-ce la sortie que vous obtenez du Javascript?

24
répondu Jon Skeet 2015-12-09 08:16:44

je pense que le plus proche que vous pouvez obtenir d'avoir des fonctions imbriquées dans Java 7 n'est pas en utilisant une classe interne anonyme (réponse de Jon Skeet ci-dessus) mais en utilisant les autres classes locales rarement utilisées. De cette façon, même l'interface de la classe imbriquée n'est pas visible en dehors de sa portée prévue et elle est un peu moins verbeuse aussi.

l'exemple de Jon Skeet mis en œuvre avec une classe locale ressemblerait à ceci:

public class Test {
    public static void main(String[] args) {
        // Hack to give us a mutable variable we can
        // change from the closure.
        final int[] mutableWrapper = { 0 };

        class Foo {
            public void bar(int num) {
                mutableWrapper[0] *= num;
                System.out.println(mutableWrapper[0]);
            }
        };

        Foo times = new Foo();

        for (int i = 1; i < 100; i++) {
            mutableWrapper[0] = i;
            times.bar(2);
            i = mutableWrapper[0];

            times.bar(i);
            i = mutableWrapper[0];
        }
    }
}

sortie:

2
4
10
100
20
répondu deinocheirus 2013-09-17 15:45:14

de telles méthodes sont parfois appelées fermetures. Jetez un oeil à Groovy – peut-être que vous le préférez à Java. En Java 8, Il y aura probablement aussi des fermetures (voir JSR335 et liste différée ).

2
répondu dma_k 2011-09-10 03:12:24

envisager de créer une classe locale anonyme et d'utiliser son bloc initialiseur pour faire le travail:

public class LocalFunctionExample {
    public static void main(final String[] args) {
        for (final int i[] = new int[] { 1 }; i[0] < 100; i[0]++) {
            new Object() {
                {
                    times(2); //multiply i by 2 and print i
                    times(i[0]); //square i and then print the result
                }

                public void times(final int num) {
                    i[0] *= num;
                    System.out.println(i[0]);
                }
            };
        }
    }
}

sortie:

2
4
10
100

(le "dernier tour de l'emballage" n'est pas automatiquement requis avec cette technique, mais était nécessaire ici pour traiter l'exigence de mutation.)

cela s'avère être presque aussi concis que la version lambda, mais vous obtenez d'utiliser n'importe quelle méthode de signatures que vous voulez, ils obtiennent d'avoir réel les noms de paramètres, et les méthodes sont appelées directement par leurs noms - pas besoin de .apply() ou autres joyeusetés. (Ce genre de chose rend parfois son travail d'outillage un peu meilleur aussi.)

0
répondu Woody Zenfell III 2017-08-03 21:42:35

je déteste utiliser le mot interdit mais vous pourriez utiliser un goto pour créer un sous-programme efficace à l'intérieur de la méthode. Il est laid et dangereux, mais beaucoup plus facile que ce qui a été montré dans les réponses précédentes. Bien que la méthode privée avec un appel à l'intérieur de la première méthode est beaucoup mieux, et vous sert a besoin très bien. Je ne sais pas pourquoi vous voulez utiliser une méthode imbriquée pour quelque chose d'aussi simple que cela.

-3
répondu michael 2013-02-27 22:48:03