Reputation: 65
I have been trying to get into functional programming with java for a few weeks now. I have created 2 functions below "validateFileFunctionally" and "validateFileRegularly" which perform same validations. First works in a functional way using predicates(we can assume Suppliers, Consumers also in here) while the second one works in traditional java ways.
In 2018 which way should I go. And should I try to use functional programming everywhere in my code as being done in "validateFileFunctionally" or only with Streams?
public class Main {
private final String INVALID_FILE_NAME_LENGTH = "INVALID FILE NAME LENGTH";
private final String INVALID_FILE_EXTENSION = "INVALID FILE EXTENSION";
private final String INVALID_FILE_SIZE = "INVALID FILE SIZE";
public static void main(String... args) {
File file = new File("text.pdf");
Main main = new Main();
main.validateFileFunctionally(file);
main.validateFileRegularly(file);
}
private void validateFileFunctionally(File file) {
BiPredicate<File, Integer> validateFileName = (f, maxLength) -> f.getName().length() < maxLength;
BiPredicate<File, String> validateExtension = (f, type) -> f.getName().endsWith(type);
BiPredicate<File, Integer> validateSize = (f, maxSize) -> f.length() <= maxSize;
BiConsumer<Boolean, String> throwExceptionIfInvalid = (isValid, errorMessage) -> {
if(!isValid) {
throw new InvalidFileException(errorMessage);
}
};
throwExceptionIfInvalid.accept(validateFileName.test(file, 20), INVALID_FILE_NAME_LENGTH);
throwExceptionIfInvalid.accept(validateExtension.test(file, ".pdf") || validateExtension.test(file, ".csv"), INVALID_FILE_EXTENSION);
throwExceptionIfInvalid.accept(validateSize.test(file, 20), INVALID_FILE_SIZE);
}
private void validateFileRegularly(File file) {
if (file.getName().length() > 20) {
throw new InvalidFileException("INVALID FILE NAME LENGTH");
} else if (!file.getName().endsWith(".pdf") && !file.getName().endsWith(".csv")) {
throw new InvalidFileException("INVALID FILE NAME LENGTH");
} else if (file.length() > 20) {
throw new InvalidFileException("INVALID FILE NAME LENGTH");
}
}
class InvalidFileException extends RuntimeException {
public InvalidFileException(String message) {
super(message);
}
}
}
Upvotes: 2
Views: 198
Reputation: 13793
You should be applying Functional Programming wherever it makes sense, and stay away from bold statements like:
"I should try to use FP everywhere in my code"
"I should code only with Streams"
However, keep in mind that this example is not functional at all - validateFileFunctionally
is just an enterprise-grade version of validateFileRegularly
Simply put, you took an imperative piece of code and rewrote it by wrapping it into FP infrastructure which is not what FP is about.
FP is about removing runtime uncertainty by building code from small and predictable building blocks/values, and not by putting lambda expressions wherever possible.
In your example, one could achieve this by abandoning exception handling and representing validation result as a value:
private Result validateFileRegularly(File file) {
if (file.getName().length() > 20) {
return Result.failed("INVALID FILE NAME LENGTH");
} else if (!file.getName().endsWith(".pdf") && !file.getName().endsWith(".csv")) {
return Result.failed("INVALID FILE NAME LENGTH");
} else if (file.length() > 20) {
return Result.failed("INVALID FILE NAME LENGTH");
}
return Result.ok();
}
Naturally, one could use the more sophisticated syntax for that, or a more sophisticated applicative-based validation API, but essentially that's what's all about.
Upvotes: 0
Reputation: 72294
Dah, this is a pet peeve of mine I'm afraid. Don't try to cram in functional stuff everywhere just because it's the latest new / cool thing - that just makes your code hard to read and unconventional. The Java 8 functional libraries are just another tool you have available that allow you to write cleaner, more concise code in a number of cases. You certainly shouldn't aim to use them exclusively.
Take your case as an example - the chained if statements still might not be the best way of achieving the above, but I can look at that and know near enough exactly what's going on in a few seconds.
Meanwhile, the functional example is just - rather odd. It's longer, less obvious as to what's going on, and offers no real advantage. I can't see a single case for using it as written in this example.
Upvotes: 2