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 FILES
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;
}
This is what i have come up with, but readability of nested code is far from good.