Langage

MethodHandles.Loop(MethodHandle[][]) Méthode

Définition

Construit un handle de méthode représentant une boucle avec plusieurs variables de boucle mises à jour et vérifiées sur chaque itération.

[Android.Runtime.Register("loop", "([[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;", "", ApiSince=33)]
public static Java.Lang.Invoke.MethodHandle? Loop(params Java.Lang.Invoke.MethodHandle[][]? clauses);
[<Android.Runtime.Register("loop", "([[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;", "", ApiSince=33)>]
static member Loop : Java.Lang.Invoke.MethodHandle[][] -> Java.Lang.Invoke.MethodHandle

Paramètres

clauses
MethodHandle[][]

tableau de tableaux (4 tuples) d’adhésion MethodHandleaux règles décrites ci-dessus.

Retours

un handle de méthode qui incarne le comportement de bouclage tel que défini par les arguments.

Attributs

Remarques

Construit un handle de méthode représentant une boucle avec plusieurs variables de boucle mises à jour et vérifiées sur chaque itération. Lors de l’arrêt de la boucle en raison de l’un des prédicats, un finaliseur correspondant est exécuté et remet le résultat de la boucle, qui est la valeur de retour du handle résultant.

Intuitivement, chaque boucle est formée par une ou plusieurs « clauses », chacune spécifiant une variable< d’itération em>locale</em> et/ou une sortie de boucle. Chaque itération de la boucle exécute chaque clause dans l’ordre. Une clause peut éventuellement mettre à jour sa variable d’itération ; il peut également effectuer un test et une sortie de boucle conditionnelle. Pour exprimer cette logique en termes de handles de méthode, chaque clause spécifie jusqu’à quatre actions indépendantes :<ul><li><em>init :</em> Before the loop executes, l’initialisation d’une variable v d’itération de type V. <li><em>step :</em> When a clause executes, an update step for the it variable v. <li><em>pred :</em> When a clause executes, a predicate execution to test for loop exit. <li><em>fini :</em> Si une clause provoque une sortie de boucle, une exécution finaliseur pour calculer la valeur de retour de la boucle. </ul> La séquence complète de tous les types de variables d’itération, dans l’ordre des clauses, sera notée comme (V...). Les valeurs elles-mêmes seront (v...). Lorsque nous parlons de « listes de paramètres », nous faisons généralement référence à des types, mais dans certains contextes (décrivant l’exécution), les listes seront de valeurs réelles.

Certaines de ces parties de clause peuvent être omises en fonction de certaines règles, et le comportement par défaut utile est fourni dans ce cas. Consultez ci-dessous pour obtenir une description détaillée.

<em>Parameters facultatif partout :</em> Chaque fonction de clause est autorisée, mais n’est pas nécessaire pour accepter un paramètre pour chaque variable vd’itération. À titre d’exception, les fonctions init ne peuvent pas prendre de v paramètres, car ces valeurs ne sont pas encore calculées lorsque les fonctions d’init sont exécutées. Toute fonction de clause peut ne pas prendre de sous-séquence de fin des paramètres qu’elle a le droit de prendre. En fait, toute fonction de clause ne peut prendre aucun argument du tout.

<Em>Loop parameters :</em> A clause function peut prendre toutes les valeurs de variable d’itération auxquelles il a droit, auquel cas il peut également prendre plus de paramètres de fin. Ces valeurs supplémentaires sont appelées <paramètres< de boucle em>>, avec leurs types et valeurs notées comme (A...) et (a...). Ils deviennent les paramètres du handle de boucle résultant, à fournir chaque fois que la boucle est exécutée. (Étant donné que les fonctions init n’acceptent pas les variables vd’itération, tout paramètre d’une fonction init est automatiquement un paramètre ade boucle .) Comme pour les variables d’itération, les fonctions de clause sont autorisées, mais pas nécessaires pour accepter les paramètres de boucle. Ces paramètres de boucle agissent comme des valeurs invariantes de boucle visibles sur toute la boucle.

<paramètres em>visibles partout :</em> Chaque fonction de clause non-init est autorisée à observer l’état de la boucle entière, car il peut être passé la liste (v... a...) complète des valeurs de variables d’itération actuelles et des paramètres de boucle entrante. Les fonctions init peuvent observer l’état initial de la pré-boucle, sous la forme (a...). La plupart des fonctions de clause n’auront pas besoin de toutes ces informations, mais elles seront officiellement connectées à celle-ci comme si.#dropArguments « astar »> Plus précisément, nous allons utiliser la notation (V*) pour exprimer un préfixe arbitraire d’une séquence (V...) complète (et de même pour (v*), , (A*)(a*)). Dans cette notation, la forme générale d’une liste de paramètres de fonction init est (A*), et la forme générale d’une liste de paramètres de fonction non-init est (V*) ou (V... A*).

<em>Checking clause structure :</em> Étant donné un ensemble de clauses, il existe un certain nombre de vérifications et d’ajustements effectués pour connecter toutes les parties de la boucle. Elles sont expliquées en détail dans les étapes ci-dessous. Dans ces étapes, chaque occurrence du mot « doit » correspond à un endroit où IllegalArgumentException sera levée si la contrainte requise n’est pas remplie par les entrées du combinateur de boucle.

<em>Effectivement des séquences identiques :</em> « effid »> Une liste A de paramètres est définie pour être <em>effectivement identique</em> à une autre liste B de paramètres si A et B sont identiques, ou si A est plus court et est identique avec un préfixe approprié de B. Lorsqu’il s’agit d’un ensemble non ordonné de listes de paramètres, nous disons que l’ensemble est « effectivement identique » dans son ensemble si l’ensemble contient une liste la plus longue et que tous les membres de l’ensemble sont effectivement identiques à cette liste la plus longue. Par exemple, tout ensemble de séquences de type du formulaire (V*) est effectivement identique et le même est vrai si d’autres séquences du formulaire (V... A*) sont ajoutées.

<em>Étape 0 : Déterminer la structure de clause.</em><ol type="a"><li>Le tableau de clauses (de type MethodHandle[][]) doit être différentnull et contenir au moins un élément. <li>Le tableau de clauses ne peut pas contenir nullde sous-tableaux ou de sous-tableaux de plus de quatre éléments. <les clauses li>plus courtes que quatre éléments sont traités comme s’ils étaient rembourrés par null des éléments à longueur quatre. Le remplissage a lieu en ajoutant des éléments au tableau. <les clauses li>avec tous les nulls sont ignorées. <li>Each clause est traitée comme un tuple de quatre tuples de fonctions, appelées « init », « step », « pred » et « fini ». </ol>

<em>Étape 1A : Déterminer les types de (V...)variables d’itération .</em><ol type="a"><li>Le type de variable d’itération pour chaque clause est déterminé à l’aide des types de retour d’init et d’étape de la clause. <li>Si les deux fonctions sont omises, il n’existe aucune variable d’itération pour la clause correspondante (void est utilisée comme type pour indiquer cela). Si l’un d’eux est omis, le type de retour de l’autre définit le type de variable d’itération de la clause. Si les deux sont donnés, le type de retour commun (ils doivent être identiques) définit le type de variable d’itération de la clause. <li>Forme la liste des types de retour (dans l’ordre des clauses), omettant toutes les occurrences de void. <li>Cette liste de types est appelée « types de variables d’itération » ((V...)). </ol>

<em>Étape 1B : Déterminer les paramètres (A...)de boucle .</em><ul><li>Examinez et collectez des listes de paramètres de fonction init (qui sont de la forme (A*)). <li>Examinez et collectez les suffixes de l’étape, des listes de paramètres prédéfini et fini, après avoir supprimé les types de variables d’itération. (Ils doivent avoir le formulaire (V... A*); collecter les (A*) parties uniquement.) <li>Ne collectez pas de suffixes à partir d’une étape, d’un pré et d’une liste de paramètres fini qui ne commencent pas par tous les types de variables d’itération. (Ces types seront archivés à l’étape 2, ainsi que tous les types de fonctions de clause.) <li>Les fonctions de clause omise sont ignorées. (Équivalent, ils sont considérés comme ayant des listes de paramètres vides.) <li>Toutes les listes de paramètres collectées doivent être identiques. <li>La liste de paramètres la plus longue (qui est nécessairement unique) est appelée « liste de paramètres externes » ((A...)). <li>S’il n’existe aucune liste de paramètres de ce type, la liste de paramètres externes est considérée comme la séquence vide. <li>La liste combinée composée de types de variables d’itération suivis des types de paramètres externes est appelée « liste de paramètres internes ». </ul>

<em>Étape 1C : déterminer le type de retour de boucle.</em><ol type="a"><li>Examinez les types de retour de fonction fini, sans tenir compte des fonctions finies omises. <li>S’il n’y a pas de fonctions finies, le type de retour de boucle est void. <dans>le cas contraire, le type R de retour commun des fonctions finies (leurs types de retour doivent être identiques) définit le type de retour de boucle. </ol>

<em>Step 1D : Vérifiez d’autres types.</em><ol type="a"><li>Il doit y avoir au moins une fonction antérieure non omise. <li>Chaque fonction antérieure non omise doit avoir un boolean type de retour. </ol>

<em>Étape 2 : Déterminer les listes de paramètres.</em><ol type="a"><li>La liste de paramètres pour le handle de boucle résultant sera la liste de (A...)paramètres externes. <li>La liste des paramètres pour les fonctions init est ajustée à la liste des paramètres externes. (Notez que leurs listes de paramètres sont déjà identiques à cette liste.) <li>La liste des paramètres pour chaque fonction non omise, non-init (étape, préd et fini) doit être effectivement identique à la liste (V... A...)de paramètres interne. </ol>

<em>Étape 3 : Renseignez les fonctions omises.</em><ol type="a"><li>If an init function is omis, use a #empty default value for the clause’s it variable type. <li>Si une fonction d’étape est omise, utilisez une fonction d’identité #identity du type de variable d’itération de la clause ; insérez des paramètres d’argument supprimés avant le paramètre de fonction d’identité pour les variables d’itérationvoid des clauses précédentes. (Cela transforme la variable de boucle en une boucle locale invariante.) <li>Si une fonction antérieure est omise, utilisez une fonction constante true . (Cela permettra de maintenir la boucle en cours, en ce qui concerne cette clause. Notez que, dans ce cas, la fonction fini correspondante est inaccessible.) <li>Si une fonction finie est omise, utilisez une valeur #empty valeur par défaut pour le type de retour de boucle. </ol>

<em>Étape 4 : Renseignez les types de paramètres manquants.</em><ol type="a"><li>À ce stade, chaque liste de paramètres de fonction init est effectivement identique à la liste (A...)de paramètres externes, mais certaines listes peuvent être plus courtes. Pour chaque fonction init avec une liste de paramètres courte, remplissez la fin de la liste. <li>À ce stade, chaque liste de paramètres de fonction non-init est effectivement identique à la liste (V... A...)de paramètres interne, mais certaines listes peuvent être plus courtes. Pour chaque fonction non-init avec une liste de paramètres courte, remplissez la fin de la liste. <Les listes d’arguments li>sont complétées par #dropArgumentsToMatch(MethodHandle, int, List, int) en supprimant les arguments de fin inutilisés. </ol>

<observations finales>.</em><ol type="a"><li>Après ces étapes, toutes les clauses ont été ajustées en fournissant des fonctions et des arguments omis. <Les fonctions li>All init ont une liste (A...)de types de paramètres commune, que le handle de boucle final aura également. <Les fonctions li>All fini ont un type Rde retour commun, que la poignée de boucle finale aura également. <Toutes>les fonctions non-init ont une liste (V... A...)de types de paramètres commune, des variables V d’itération (non)voidsuivies de paramètres de boucle. <li>Chaque paire de fonctions d’init et d’étape accepte leur type Vde retour. <Li>Chaque fonction non-init peut observer les valeurs (v...) actuelles de toutes les variables d’itération. <li>Chaque fonction peut observer les valeurs (a...) entrantes de tous les paramètres de boucle. </ol>

<exemple em>.</em> En conséquence de l’étape 1A ci-dessus, le loop combinateur a la propriété suivante : <ul><li>Given N clauses Cn = {null, Sn, Pn} with n = 1..N. <li>Supposez que les handles Pn de prédicat sont soit n’aient null aucun paramètre. (Une seule Pn doit être non-null.) <li>Supposez que les handles d’étape ont des Sn signatures (B1..BX)Rn, pour une constante X>=N. <li>Suppose est Q le nombre de types Rnnon vides, et (V1...VQ) est la séquence de ces types. <li>Il doit être que Vn == Bn pour n = 1..min(X,Q). <li>Les types de Vn paramètres seront interprétés comme des éléments (V...)d’état local de boucle. <li>Tous les types BQ+1..BX restants (si Q<X) déterminent les types (A...)de paramètres du handle de boucle résultant. </ul> Dans cet exemple, les paramètres (A...) de handle de boucle ont été dérivés des fonctions d’étape, ce qui est naturel si la plupart des calculs de boucle se produisent dans les étapes. Pour certaines boucles, le fardeau du calcul peut être le plus lourd dans les fonctions antérieures, et les fonctions prédées peuvent donc avoir besoin d’accepter les valeurs des paramètres de boucle. Pour les boucles avec une logique de sortie complexe, les fonctions finies peuvent avoir besoin d’accepter des paramètres de boucle, et de même pour les boucles avec une logique d’entrée complexe, où les fonctions init auront besoin des paramètres supplémentaires. Pour de telles raisons, les règles de détermination de ces paramètres sont aussi symétriques que possible, dans toutes les parties de clause. En général, les paramètres de la boucle fonctionnent comme des valeurs invariantes courantes sur toute la boucle, tandis que les variables d’itération fonctionnent comme valeurs variant communes, ou (s’il n’y a pas de fonction d’étape) en tant que boucle interne invariante temporaire.

<exécution de boucle em>.</em><ol type="a"><li>When the loop is called, the loop input values are saved in locals, to be passed to each clause function. Ces locaux sont invariants de boucle. <La fonction li>Each init est exécutée dans l’ordre de clause (en passant les arguments externes) et les valeurs non-valeursvoid sont enregistrées (a...)(en tant que variables (v...)d’itération) dans les variables locales. Ces variables locales varient (sauf si leurs étapes se comportent en tant que fonctions d’identité, comme indiqué ci-dessus). <Li>Toutes les exécutions de fonction (à l’exception des fonctions init) sont passées à la liste des paramètres internes, composées des valeurs (v...) non itérationvoid (dans l’ordre de clause), puis des entrées de boucle (dans l’ordre des arguments (a...) ). <li>L’étape et les fonctions antérieures sont ensuite exécutées, dans l’ordre des clauses (étape avant prédéfini), jusqu’à ce qu’une fonction prédéfinie retourne false. <li>Le résultat nonvoid résultant d’un appel de fonction d’étape est utilisé pour mettre à jour la valeur correspondante dans la séquence (v...) de variables de boucle. La valeur mise à jour est immédiatement visible pour tous les appels de fonction suivants. <li>Si une fonction prédéfini retourne false, la fonction finie correspondante est appelée et la valeur résultante (de type R) est retournée à partir de la boucle dans son ensemble. <li>Si toutes les fonctions prédéfinis retournent toujours true, aucune fonction finie n’est jamais appelée, et la boucle ne peut pas se quitter, sauf en lève une exception. </ol>

<conseils d’utilisation em>.</em><ul><li>Bien que chaque fonction d’étape reçoive les valeurs actuelles d’em>all</em> les variables de <boucle, parfois une fonction d’étape doit uniquement observer la valeur actuelle de sa propre variable. Dans ce cas, la fonction d’étape peut avoir besoin de #dropArguments supprimer explicitement toutes les variables de boucle précédentes. Cela nécessite la mention de leurs types, dans une expression telle que dropArguments(step, 0, V0.class, ...). <les variables de boucle li>ne sont pas requises pour varier ; elles peuvent être invariantes de boucle. Une clause peut créer une boucle invariante par une fonction init appropriée sans étape, prédéfinie ou fonction finie. Cela peut être utile pour « wire » un argument de boucle entrant dans l’étape ou la fonction antérieure d’une variable de boucle adjacente. <li>Si certaines des fonctions de clause sont des méthodes virtuelles sur une instance, l’instance elle-même peut être placée de manière pratique dans une boucle invariante initiale « variable », à l’aide d’une clause initiale telle que new MethodHandle[]{identity(ObjType.class)}. Dans ce cas, la référence d’instance sera la première valeur de variable d’itération, et il sera facile d’utiliser des méthodes virtuelles en tant que parties de clause, car toutes ces dernières prendront une référence d’instance de référence de premier plan correspondant à cette valeur. </ul>

Voici le pseudocode pour le handle de boucle résultant. Comme ci-dessus, V et v représente les types et valeurs des variables de boucle ; A et a représentent les arguments passés à la boucle entière ; et R est le type de résultat commun de tous les finaliseurs ainsi que de la boucle résultante. <blockquote>

{@code
            V... init...(A...);
            boolean pred...(V..., A...);
            V... step...(V..., A...);
            R fini...(V..., A...);
            R loop(A... a) {
              V... v... = init...(a...);
              for (;;) {
                for ((v, p, s, f) in (v..., pred..., step..., fini...)) {
                  v = s(v..., a...);
                  if (!p(v..., a...)) {
                    return f(v..., a...);
                  }
                }
              }
            }
            }

</blockquote> Notez que les listes (V...) de types de paramètres et (A...) ont été étendues à leur longueur entière, même si les fonctions de clause individuelles peuvent ne pas les prendre toutes. Comme indiqué ci-dessus, les paramètres manquants sont renseignés comme si par #dropArgumentsToMatch(MethodHandle, int, List, int).

Ajouté dans 9.

Java documentation pour java.lang.invoke.MethodHandles.loop(java.lang.invoke.MethodHandle[]...).

Les parties de cette page sont des modifications basées sur le travail créé et partagé par Android Open Source et utilisées en fonction des termes décrits dans la Creative Commons 2.5 Attribution License.

S’applique à