MOTIVATION
On a youtube video of Venkat Subramaniam, he tells about how not use AutoCloseable, but try to use a function like "use". Because, one may forget to implement try block on a class which implements AutoCloseable.
QUESTION
I have implemented this strategy on many cases, however there is one case that I could not able to.
I have many file writers according to their file types. All of them uses same interface. So main macro code can be parsed and file actions can be processed for every kind of file types. (on the blog, I have reduced the function names to only "addText" and file-types as 2: "FileWeb" and "FileTable".)
And, users decides which type of files they want on everytime.
The sequencial way of doing is as below. (There, in function "constructFileAccordingToMacroCode", "the parsing of macrocode line by line" is processed twice).
{//SEQUENTIAL boolean produceFileTable = true; if (produceFileTable) { FileTable.use(dir, fileLabel, fileTable -> { constructFileAccordingToMacroCode(macroCode, fileTable); }); } boolean produceFileWeb = true; if (produceFileWeb) { FileWeb.use(dir, fileLabel, fileWeb -> { constructFileAccordingToMacroCode(macroCode, fileWeb); }); }}Kind of parallel way of doing is as below. (There, the function "constructFileAccordingToMacroCode" runs once, hence, "the parsing of macrocode line by line" is processed once).
{//KIND OF PARALLEL boolean produceFileTable = true;//? boolean produceFileWeb = true;//? FileTable.use(dir, fileLabel, fileTable -> { FileWeb.use(dir, fileLabel, fileWeb -> { constructFileAccordingToMacroCode(macroCode, fileTable, fileWeb); }); });}However, If I am gonna implement it, I will lose the option of not creating the unwanted file types.
Is there more smart way of doing things?
RELEVANT EXAMPLE CLASS FILESgithub
Main
public class Main { public static void main(String... s) { var macroCode = """ LINE1: ADD_FILE_TYPE LINE2: ADD_SYSTEM_MILLIS"""; var dir = Path.of("c:\\fileFirectory"); var fileLabel = "fileLabel"; {//SEQUENTIAL boolean produceFileTable = true; if (produceFileTable) { FileTable.use(dir, fileLabel, fileTable -> { constructFileAccordingToMacroCode(macroCode, fileTable); }); } boolean produceFileWeb = true; if (produceFileWeb) { FileWeb.use(dir, fileLabel, fileWeb -> { constructFileAccordingToMacroCode(macroCode, fileWeb); }); } } {//KIND OF PARALLEL boolean produceFileTable = true;//? boolean produceFileWeb = true;//? FileTable.use(dir, fileLabel, fileTable -> { FileWeb.use(dir, fileLabel, fileWeb -> { constructFileAccordingToMacroCode(macroCode, fileTable, fileWeb); }); }); } } private static boolean constructFileAccordingToMacroCode(String macroCode, FileInterface... files) { boolean result; for (var file : files) { //parse macroCode line by line in a for loop { /*FOREXAMPLE LINE1: from macroCode*/ result = file.addText("I am a %s type file.".formatted(file.getClass().getSimpleName())); if (!result) { return false; } /*FOREXAMPLE LINE2: from macroCode*/ file.addText(", and time is %L".formatted(System.currentTimeMillis())); if (!result) { return false; } //} } return true; }}TGS_RunnableType1
public interface TGS_RunnableType1<A> { public void run(A result);}FileInterface
public interface FileInterface /*implements AutoCloseable*/{ public boolean addText(CharSequence text);}FileTable
public class FileTable implements FileInterface { private FileTable(Path dir) { this.dir = dir; } final public Path dir; @Override public boolean addText(CharSequence text) { //TODO add text code return true; } public static void use(Path dir, String fileLabel, TGS_RunnableType1<FileTable> fileTable) { var instance = new FileTable(dir); try { instance.open(); fileTable.run(instance); instance.close(); } catch (Exception e) {//SILENTLY CLOSE try { instance.close(); } catch (Exception e2) { if (e2 instanceof InterruptedException) {//let InterruptedException propagate throw e2; } } if (e instanceof InterruptedException) {//let InterruptedException propagate throw e; } } } private void open() { //open according to dir & fileLabel & type } private void close() { //close according to dir & fileLabel & type }}FileWeb
public class FileWeb implements FileInterface { private FileWeb(Path dir) { this.dir = dir; } final public Path dir; @Override public boolean addText(CharSequence text) { //TODO add text code return true; } public static void use(Path dir, String fileLabel, TGS_RunnableType1<FileWeb> fileWeb) { var instance = new FileWeb(dir); try { instance.open(); fileWeb.run(instance); instance.close(); } catch (Exception e) {//SILENTLY CLOSE try { instance.close(); } catch (Exception e2) { if (e2 instanceof InterruptedException) {//let InterruptedException propagate throw e2; } } if (e instanceof InterruptedException) {//let InterruptedException propagate throw e; } } } private void open() { //open according to dir & fileLabel & type } private void close() { //close according to dir & fileLabel & type }------------------------- UPDATE ----------------
PARALLEL VERSION OF constructFileAccordingToMacroCode
//WILL POSSIBLY CREATE OUT OF MEMORY ERROR private static boolean constructFileAccordingToMacroCode(String macroCode, FileInterface... files) { //parse macroCode line by line in a for loop { var errorPresent = IntStream.range(0, files.length).parallel() .mapToObj(i -> { var file = files[i]; /*FOREXAMPLE LINE1: from macroCode*/ var result = file.addText("I am a %s type file.".formatted(file.getClass().getSimpleName())); if (!result) { return false; } /*FOREXAMPLE LINE2: from macroCode*/ file.addText(", and time is %L".formatted(System.currentTimeMillis())); if (!result) { return false; } return true; }) .filter(result -> false) .findAny().isPresent(); if (errorPresent) { return false; } //} return true; }