diff --git a/trampoline/README.md b/trampoline/README.md index 849cc663e..4a4030f39 100644 --- a/trampoline/README.md +++ b/trampoline/README.md @@ -24,15 +24,17 @@ and to interleave the execution of functions without hard coding them together o Use the Trampoline pattern when * For implementing tail recursive function. This pattern allows to switch on a stackless operation. -* For to interleaving the execution of two or more functions on the same thread. +* For interleaving the execution of two or more functions on the same thread. ## Known uses(real world examples) * Trampoline refers to using reflection to avoid using inner classes, for example in event listeners. The time overhead of a reflection call is traded for the space overhead of an inner class. Trampolines in Java usually involve the creation of a GenericListener to pass events to an outer class. + ## Credits * [Trampolining: a practical guide for awesome Java Developers](https://medium.com/@johnmcclean/trampolining-a-practical-guide-for-awesome-java-developers-4b657d9c3076) * [Trampoline in java ](http://mindprod.com/jgloss/trampoline.html) +* [cyclops-react](https://github.com/aol/cyclops-react) diff --git a/trampoline/src/main/java/com/iluwatar/trampoline/App.java b/trampoline/src/main/java/com/iluwatar/trampoline/App.java deleted file mode 100644 index 8afda31a7..000000000 --- a/trampoline/src/main/java/com/iluwatar/trampoline/App.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.iluwatar.trampoline; - -public class App { -} diff --git a/trampoline/src/main/java/com/iluwatar/trampoline/Trampoline.java b/trampoline/src/main/java/com/iluwatar/trampoline/Trampoline.java new file mode 100644 index 000000000..3be44ebba --- /dev/null +++ b/trampoline/src/main/java/com/iluwatar/trampoline/Trampoline.java @@ -0,0 +1,84 @@ +package com.iluwatar.trampoline; + +import java.util.stream.Stream; + +/**When get is called on the returned Trampoline, internally it will iterate calling ‘jump’ + on the returned Trampoline as long as the concrete instance returned is More, + stopping once the returned instance is Done. Essential we convert looping via recursion into iteration, + the key enabling mechanism is the fact that Trampoline.more is a lazy operation. + Trampoline in cyclops-react extends java.util.Supplier. Calling Trampoline.more we are basically creating + a Supplier that defers the actual recursive call, and having defered the call we can move it outside of the recursive loop. + This means we can define algorithms recursively in Java but execute them iteratively.*/ + +public interface Trampoline { + T get(); + + + /** + * @return next stage + */ + default Trampoline jump() { + return this; + } + + + default T result() { + return get(); + } + + /** + * @return true if complete + * + */ + default boolean complete() { + return true; + } + + /** + * Created a completed Trampoline + * + * @param result Completed result + * @return Completed Trampoline + */ + static Trampoline done(final T result) { + return () -> result; + } + + + /** + * Create a Trampoline that has more work to do + * + * @param trampoline Next stage in Trampoline + * @return Trampoline with more work + */ + static Trampoline more(final Trampoline> trampoline) { + return new Trampoline() { + @Override + public boolean complete() { + return false; + } + + @Override + public Trampoline jump() { + return trampoline.result(); + } + + @Override + public T get() { + return trampoline(this); + } + + T trampoline(final Trampoline trampoline) { + + return Stream.iterate(trampoline, Trampoline::jump) + .filter(Trampoline::complete) + .findFirst() + .get() + .result(); + + } + }; + } + + +} diff --git a/trampoline/src/main/java/com/iluwatar/trampoline/TrampolineApp.java b/trampoline/src/main/java/com/iluwatar/trampoline/TrampolineApp.java new file mode 100644 index 000000000..d629f7a84 --- /dev/null +++ b/trampoline/src/main/java/com/iluwatar/trampoline/TrampolineApp.java @@ -0,0 +1,67 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.trampoline; + + +import lombok.extern.slf4j.Slf4j; + +/** + *
+ * By representing a computation in one of 2 states + (completed with result, or a reference to the reminder of the computation, + something like the way a java.util.Supplier does) + it is possible to implement algorithms recursively in Java without blowing the stack + and to interleave the execution of functions without hard coding them together or even using threads. +
+
+ Trampoline has 2 state : [done], [ more] +
+ When get is called on the returned Trampoline, internally it will iterate calling ‘jump’ + on the returned Trampoline as long as the concrete instance returned is More, + stopping once the returned instance is Done. Essential we convert looping via recursion into iteration, + the key enabling mechanism is the fact that Trampoline.more is a lazy operation. + Trampoline in cyclops-react extends java.util.Supplier. Calling Trampoline.more we are basically creating + a Supplier that defers the actual recursive call, and having defered the call we can move it outside of the recursive loop. + This means we can define algorithms recursively in Java but execute them iteratively. + */ + +@Slf4j +public class TrampolineApp { + public static void main(String[] args) { + log.info("start pattern"); + Integer result = loop(10, 1).result(); + log.info("result {}" ,result); + + } + /** + * Manager for pattern. + * */ + public static Trampoline loop(int times,int prod){ + if(times==0) + return Trampoline.done(prod); + else + return Trampoline.more(()->loop(times-1,prod*times)); + } + +} diff --git a/trampoline/src/test/java/com/iluwatar/trampoline/TrampolineAppTest.java b/trampoline/src/test/java/com/iluwatar/trampoline/TrampolineAppTest.java new file mode 100644 index 000000000..fb7fc09ee --- /dev/null +++ b/trampoline/src/test/java/com/iluwatar/trampoline/TrampolineAppTest.java @@ -0,0 +1,17 @@ +package com.iluwatar.trampoline; + +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class TrampolineAppTest { + + @Test + public void test()throws IOException{ + int result = TrampolineApp.loop(10, 1).result(); + assertEquals("Be equal",3628800,result); + } + +} \ No newline at end of file