diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 8378ab9e1c3..535a7781cf7 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -3463,7 +3463,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * return zip; * } * // assume MH_initZip, MH_zipPred, and MH_zipStep are handles to the above methods - * MethodHandle loop = MethodHandles.doWhileLoop(MH_initZip, MH_zipPred, MH_zipStep); + * MethodHandle loop = MethodHandles.doWhileLoop(MH_initZip, MH_zipStep, MH_zipPred); * List a = Arrays.asList("a", "b", "c", "d"); * List b = Arrays.asList("e", "f", "g", "h"); * List zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h"); @@ -3602,7 +3602,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * String start(String arg) { return arg; } * String step(int counter, String v, String arg) { return "na " + v; } * // assume MH_start and MH_step are handles to the two methods above - * MethodHandle loop = MethodHandles.countedLoop(13, MH_start, MH_step); + * MethodHandle fit13 = MethodHandles.constant(int.class, 13); + * MethodHandle loop = MethodHandles.countedLoop(fit13, MH_start, MH_step); * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!")); * } * @@ -3742,11 +3743,11 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * @apiNote Example: *
{@code
      * // reverse a list
-     * List reverseStep(String e, List r) {
+     * List reverseStep(String e, List r, List l) {
      *   r.add(0, e);
      *   return r;
      * }
-     * List newArrayList() { return new ArrayList<>(); }
+     * List newArrayList(List l) { return new ArrayList<>(); }
      * // assume MH_reverseStep, MH_newArrayList are handles to the above methods
      * MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);
      * List list = Arrays.asList("a", "b", "c", "d", "e");
diff --git a/jdk/test/java/lang/invoke/JavaDocExamplesTest.java b/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
index b94f2f04ea8..9a4b3f3624b 100644
--- a/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
+++ b/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
@@ -29,6 +29,7 @@
 
 package test.java.lang.invoke;
 
+import java.io.StringWriter;
 import java.lang.invoke.*;
 import static java.lang.invoke.MethodHandles.*;
 import static java.lang.invoke.MethodType.*;
@@ -36,7 +37,6 @@ import static java.lang.invoke.MethodType.*;
 import java.util.*;
 
 import org.testng.*;
-import static org.testng.AssertJUnit.*;
 import org.testng.annotations.*;
 
 /**
@@ -322,6 +322,13 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
         Assert.assertEquals(exp, act);
     }
 
+    static void assertTrue(boolean b) {
+        if (verbosity > 0) {
+            System.out.println("result: " + b);
+        }
+        Assert.assertTrue(b);
+    }
+
     @Test public void testMethodHandlesSummary() throws Throwable {
         {{
 {} /// JAVADOC
@@ -639,6 +646,165 @@ assert(!(boolean) invokeDispatched.invokeExact(y, "hasNext", "[123]+[789]"));
             }}
     }
 
+    static int one(int k) { return 1; }
+    static int inc(int i, int acc, int k) { return i + 1; }
+    static int mult(int i, int acc, int k) { return i * acc; }
+    static boolean pred(int i, int acc, int k) { return i < k; }
+    static int fin(int i, int acc, int k) { return acc; }
+
+    @Test public void testLoop() throws Throwable {
+        MethodHandle MH_inc, MH_one, MH_mult, MH_pred, MH_fin;
+        Class I = int.class;
+        MH_inc = LOOKUP.findStatic(THIS_CLASS, "inc", methodType(I, I, I, I));
+        MH_one = LOOKUP.findStatic(THIS_CLASS, "one", methodType(I, I));
+        MH_mult = LOOKUP.findStatic(THIS_CLASS, "mult", methodType(I, I, I, I));
+        MH_pred = LOOKUP.findStatic(THIS_CLASS, "pred", methodType(boolean.class, I, I, I));
+        MH_fin = LOOKUP.findStatic(THIS_CLASS, "fin", methodType(I, I, I, I));
+        {{
+{} /// JAVADOC
+// iterative implementation of the factorial function as a loop handle
+// null initializer for counter, should initialize to 0
+MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
+MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
+MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
+assertEquals(120, loop.invoke(5));
+{}
+        }}
+    }
+
+    static List initZip(Iterator a, Iterator b) { return new ArrayList<>(); }
+    static boolean zipPred(List zip, Iterator a, Iterator b) { return a.hasNext() && b.hasNext(); }
+    static List zipStep(List zip, Iterator a, Iterator b) {
+        zip.add(a.next());
+        zip.add(b.next());
+        return zip;
+    }
+
+    @Test public void testWhileLoop() throws Throwable {
+        MethodHandle MH_initZip, MH_zipPred, MH_zipStep;
+        Class IT = Iterator.class;
+        Class L = List.class;
+        MH_initZip = LOOKUP.findStatic(THIS_CLASS, "initZip", methodType(L, IT, IT));
+        MH_zipPred = LOOKUP.findStatic(THIS_CLASS, "zipPred", methodType(boolean.class, L, IT, IT));
+        MH_zipStep = LOOKUP.findStatic(THIS_CLASS, "zipStep", methodType(L, L, IT, IT));
+        {{
+{} /// JAVADOC
+// implement the zip function for lists as a loop handle
+MethodHandle loop = MethodHandles.doWhileLoop(MH_initZip, MH_zipStep, MH_zipPred);
+List a = Arrays.asList("a", "b", "c", "d");
+List b = Arrays.asList("e", "f", "g", "h");
+List zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h");
+assertEquals(zipped, (List) loop.invoke(a.iterator(), b.iterator()));
+{}
+        }}
+    }
+
+    static int zero(int limit) { return 0; }
+    static int step(int i, int limit) { return i + 1; }
+    static boolean pred(int i, int limit) { return i < limit; }
+
+    @Test public void testDoWhileLoop() throws Throwable {
+        MethodHandle MH_zero, MH_step, MH_pred;
+        Class I = int.class;
+        MH_zero = LOOKUP.findStatic(THIS_CLASS, "zero", methodType(I, I));
+        MH_step = LOOKUP.findStatic(THIS_CLASS, "step", methodType(I, I, I));
+        MH_pred = LOOKUP.findStatic(THIS_CLASS, "pred", methodType(boolean.class, I, I));
+        {{
+{} /// JAVADOC
+// int i = 0; while (i < limit) { ++i; } return i; => limit
+MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);
+assertEquals(23, loop.invoke(23));
+{}
+        }}
+    }
+
+    static String start(String arg) { return arg; }
+    static String step(int counter, String v, String arg) { return "na " + v; }
+
+    @Test public void testCountedLoop() throws Throwable {
+        MethodHandle MH_start, MH_step;
+        Class S = String.class;
+        MH_start = LOOKUP.findStatic(THIS_CLASS, "start", methodType(S, S));
+        MH_step = LOOKUP.findStatic(THIS_CLASS, "step", methodType(S, int.class, S, S));
+        {{
+{} /// JAVADOC
+// String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
+// => a variation on a well known theme
+MethodHandle fit13 = MethodHandles.constant(int.class, 13);
+MethodHandle loop = MethodHandles.countedLoop(fit13, MH_start, MH_step);
+assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
+{}
+        }}
+    }
+
+    static List reverseStep(String e, List r, List l) {
+        r.add(0, e);
+        return r;
+    }
+    static List newArrayList(List l) { return new ArrayList<>(); }
+
+    @Test public void testIteratedLoop() throws Throwable {
+        MethodHandle MH_newArrayList, MH_reverseStep;
+        Class L = List.class;
+        MH_newArrayList = LOOKUP.findStatic(THIS_CLASS, "newArrayList", methodType(L, L));
+        MH_reverseStep = LOOKUP.findStatic(THIS_CLASS, "reverseStep", methodType(L, String.class, L, L));
+        {{
+{} /// JAVADOC
+// reverse a list
+MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);
+List list = Arrays.asList("a", "b", "c", "d", "e");
+List reversedList = Arrays.asList("e", "d", "c", "b", "a");
+assertEquals(reversedList, (List) loop.invoke(list));
+{}
+        }}
+    }
+
+    @Test public void testFoldArguments3() throws Throwable {
+        {{
+{} /// JAVADOC
+MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+        "println", methodType(void.class, String.class))
+        .bindTo(System.out);
+MethodHandle cat = lookup().findVirtual(String.class,
+        "concat", methodType(String.class, String.class));
+assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+MethodHandle catTrace = foldArguments(cat, 1, trace);
+// also prints "jum":
+assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+{}
+        }}
+    }
+
+    @Test public void testAsCollector2() throws Throwable {
+        {{
+{} /// JAVADOC
+StringWriter swr = new StringWriter();
+MethodHandle swWrite = LOOKUP.findVirtual(StringWriter.class, "write", methodType(void.class, char[].class, int.class, int.class)).bindTo(swr);
+MethodHandle swWrite4 = swWrite.asCollector(0, char[].class, 4);
+swWrite4.invoke('A', 'B', 'C', 'D', 1, 2);
+assertEquals("BC", swr.toString());
+swWrite4.invoke('P', 'Q', 'R', 'S', 0, 4);
+assertEquals("BCPQRS", swr.toString());
+swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);
+assertEquals("BCPQRSZ", swr.toString());
+{}
+        }}
+    }
+
+    @Test public void testAsSpreader2() throws Throwable {
+        {{
+{} /// JAVADOC
+MethodHandle compare = LOOKUP.findStatic(Objects.class, "compare", methodType(int.class, Object.class, Object.class, Comparator.class));
+MethodHandle compare2FromArray = compare.asSpreader(0, Object[].class, 2);
+Object[] ints = new Object[]{3, 9, 7, 7};
+Comparator cmp = (a, b) -> a - b;
+assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 0, 2), cmp) < 0);
+assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 1, 3), cmp) > 0);
+assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp) == 0);
+{}
+        }}
+    }
+
     /* ---- TEMPLATE ----
     @Test public void testFoo() throws Throwable {
         {{