1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | package Torello.Java.JSON; import java.util.function.Supplier; import java.util.function.Consumer; import Torello.Java.Additional.EffectivelyFinal; import java.util.stream.Stream; import java.util.stream.IntStream; import java.util.stream.LongStream; import java.util.stream.DoubleStream; // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // SettingsRec is configured to produce a Stream, or an Array // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // // The purpose of this class is to generate the three Function-Poiters that are needed to process // the output of a Json-Array. The general purpose class "ProcessJsonArray" handles all of the // different variants of that are offered for processing a Json-Array. In order to do this, // Java's "Function-Pointers" (which are called "Functional-Interfaces" in Java-Speak) are utilized // quite extensively in this package. // // This class looks really cryptic, and hard to read. HOWEVER - IT IS LITERALLY DOING ALMOST // NOTHING !! // // All that is accomplished is the "wrapping" of the Standard Java Stream-Methods: // * Stream.builder() // * Stream.Builder.accept() // * Stream.Builder.build() // // Into "Lambda's" that are saved as the three fields of this class. NO MORE NO LESS ! // // Oh, and lastly, because the JDK does, indeed, provide three "Primitive Streams" // -> IntStream, LongStream, DoubleStream // // This class also provides three "alternate static builders" which generate lambda-wrappers for // * IntStream.builder() // * IntStrea.Builder.accept() // * IntStream.Builder.build() // // And that goes double for "LongStream", and triple for "DoubleStream" // // That's all this class does. These "Wrappers" allow the MAIN PROCESSING LOOP - ProcessJsonArray // to treat a User-Request for output sent to a "Stream", "Consumer" or "Array" in the exact same // way, and using the exact same code. // // // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Details regarding Java's "Function Pointers" or "Method Pointers" // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // // This class is used to produce three "Lambdas" or "Functional-Interfaces". Merely because this // Json-Package creates quite a few "Method Pointers" or "Function Poiters" (which is all that a // Functional-Interface even is) - the contents of the Helper-Classes in this package all look all // a little bit cryptic. These are cryptic simply because the "Lambda-Syntax" is pretty well // designed, but does, indeed, hide or cover up who-what-when-where these methods are actually ever // invoked. // // In a nutshell, there is simply no way to see who or what actually is calling the "acceptor", // or the "constructNewBuilder" or "runBuilderDotBuild". However, because the puporse of these // Array-Processing Loops is to be able to handle all variations on User-Requested Handlers by // using the exact same code - it is imperative to use Java's Function-Pointers, and it is not // feasible to get away from them (although it would make the code a lot more readable to do so). // // However, quite literally, the only purpose of this little helper class is to produce or generate // the three Lambda's - which are all saved as fields in this class. // // // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Re-Using a SettingsRec instance with "ProcessJsonArray": // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // // This is the "Second Major Reason" for this Helper-Class... // // The value of exposing the "SettingsRec" Object to the API is that it allows the user to get an // instance of this class, in a way that does not require the User to buid a new Settings // Configuration Record each and every time that a Json-Array needs to be processed. Creating an // istance of the "SettingsRec" class, while not very expensive, still requires some amount of // extraneously Object-Creating of Objects which are quite short-lived, and become "extra work" // for the Garbage-Collector / Memory-Manager. // // Creating an instance of "SettingsRec" that is conforms to all of the User's Flags & Default // Values once, and then using that same record - over and over again - is, indeed, more // efficient programming. THE ONLY CATCH IS THAT - IN THE CASE OF STREAMS - a new // Stream.Builder (or IntStream.Builder) instance needs to be constructed each and every time // that "ProcessJsonArray". // // By Saving a "Wrapper" around the methods around 1) Stream.builder(), 2) Stream.Builder.accept() // and 3) Stream.Builder.build() - reusing the SettingsRec is now a breeze! // // // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // The classes which invoke this helper include: // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // // * RJArrIntoStream, -> invokes method 'normalStream()' **ONLY** // * RJArrIntoBoxedStream -> invokes method 'normalStream()' **ONLY** // * RJArrIntoPrimStream -> invokes 'intStream()', 'longStream()', 'doubleStream()' // * RJArrDimN -> invokes all of these class STREAM_BUILDER<DATA_TYPE, STREAM_TYPE> { // ******************************************************************************************** // ******************************************************************************************** // Fields // ******************************************************************************************** // ******************************************************************************************** final Consumer<DATA_TYPE> acceptor; // Stream.Builder.accept final Runnable constructNewBuilder; // Stream.builder() final Supplier<STREAM_TYPE> runBuilderDotBuild; // Stream.Builder.build() // ******************************************************************************************** // ******************************************************************************************** // Class Lone Constructor, Declared **PRIVATE** // ******************************************************************************************** // ******************************************************************************************** // This **PRIVATE** Constructor is only used by the four Package-Privte Static-Builder Methods // which are provided below. private STREAM_BUILDER( final Consumer<DATA_TYPE> acceptor, final Runnable constructNewBuilder, final Supplier<STREAM_TYPE> runBuilderDotBuild ) { this.acceptor = acceptor; this.constructNewBuilder = constructNewBuilder; this.runBuilderDotBuild = runBuilderDotBuild; } // ******************************************************************************************** // ******************************************************************************************** // Static-Builder Methods, these invoke this class lone constructor (included directly above) // ******************************************************************************************** // ******************************************************************************************** static <X> STREAM_BUILDER<X, Stream<X>> normalStream() { final EffectivelyFinal<Stream.Builder<X>> EF = new EffectivelyFinal<>(null); return new STREAM_BUILDER<>( (X x) -> EF.f.accept(x), // final Consumer<DATA_TYPE> acceptor; () -> EF.f = Stream.builder(), // final Runnable constructNewBuilder; () -> EF.f.build() // final Supplier<STREAM_TYPE> runBuilderDotBuild; ); } // Generates "Method Pointers" which are consistent with Java's "IntStream" Class static STREAM_BUILDER<Integer, IntStream> intStream() { final EffectivelyFinal<IntStream.Builder> EF = new EffectivelyFinal<>(null); return new STREAM_BUILDER<>( (Integer i) -> EF.f.accept(i.intValue()), // final Consumer<DATA_TYPE> acceptor; () -> EF.f = IntStream.builder(), // final Runnable constructNewBuilder; () -> EF.f.build() // final Supplier<STREAM_TYPE> ); // runBuilderDotBuild; } // Generates "Method Pointers" which are consistent with Java's "LongStream" Class static STREAM_BUILDER<Long, LongStream> longStream() { final EffectivelyFinal<LongStream.Builder> EF = new EffectivelyFinal<>(null); return new STREAM_BUILDER<>( (Long l) -> EF.f.accept(l.longValue()), // final Consumer<DATA_TYPE> acceptor; () -> EF.f = LongStream.builder(), // final Runnable constructNewBuilder; () -> EF.f.build() // final Supplier<STREAM_TYPE> ); // runBuilderDotBuild; } // Generates "Method Pointers" which are consistent with Java's "DoubleStream" Class static STREAM_BUILDER<Double, DoubleStream> doubleStream() { final EffectivelyFinal<DoubleStream.Builder> EF = new EffectivelyFinal<>(null); return new STREAM_BUILDER<>( (Double d) -> EF.f.accept(d.doubleValue()), // final Consumer<DATA_TYPE> acceptor; () -> EF.f = DoubleStream.builder(), // final Runnable constructNewBuilder; () -> EF.f.build() // final Supplier<STREAM_TYPE> ); // runBuilderDotBuild; } } |