Functional interfaces have been provided since java8, but how much do you use them in your products? In the case of a product that is already running, it may be difficult to migrate in many cases, but I felt that there are many merits when actually using it in the product, so this time I actually used the original (functional interface). (No) Let's rewrite the sample code using the functional interface.
The following is the processing flow of the similar image judgment method given as an example. It is said that empty is described as a difference, but null is returned if functional I / F is not used, and Optional.empty is returned if it is used.
Similar image judgment method processing flow
Search images from DB by image hash value
_____________↓____________
↓ Yes ↓ None
Return image data ↓
Search for candidates from additional information in the image
↓ Yes ↓ None
↓ ↓
Search for similar images ↓
________↓_____Empty return
↓ Yes ↓ None
↓ ↓
Return similar image data Empty return
Let's implement the above flow without using functional I / F. Below is a code example.
Functional I/F unused
/**
* @param imageHash image hash value
* @param addInfo Image add information
* @return
*/
public SimilarImageDto getImage(String imageHash, AddInfo addInfo) {
//Search by exact match
val image = imageRepository.get(imageHash)
//If it exists, generate a Dto and return it
if ( image != null ) {
return SimilarImageDto.create(image);
//Processing when it does not exist
} else {
//Search for candidate images from additional information
List<ImageInfo> imgInfoList = imageInfoRepository.find(addInfo);
//Similarity judgment from candidates. If it does not exist, null is returned.
if (CollectionUtils.isEmpty(imgInfoList) ) {
return null;
}
for (ImageInfo imgInfo : imgInfoList) {
//If a similar image exists, generate a Dto and return it
if( isSimilar(imgInfo) ){
return SimilarImageDto.create(imgInfo);
}
}
return null;
}
}
//Similar image judgment function
private boolean isSimilar(ImageInfo imgInfo) = {
//Similar image search processing
return isSimilar;
};
Let's implement the above flow using functional I / F. Below is a code example.
Functional I/Use F
/**
* @param imgHash image hash value
* @param addInfo Image add information
* @return
*/
public Optional<SimilarImageDto> getImageOpt(String imgHash, AddInfo addInfo) {
return imageRepository //
.getOpt(imgHash) //Search by exact match
.map(img -> SimilarImageDto.create(img) )//If it exists, generate a Dto and return it
.orElseGet(() -> { //Processing when it does not exist
return imageInfoRepository.find(addInfo) //Search for candidate images from additional information
.detectOptional( imgInfo -> predicateSimilar.test(imgInfo) )//Similarity judgment from candidates. Optional if not present.empty is returned.
.map( imgInfo -> SimilarImageDto.create(imgInfo) );//If a similar image exists, generate a Dto and return it
});
}
//Similar image judgment function
private Predicate<ImageInfo> predicateSimilar = imgInfo -> {
//Similar image search processing
return isSimilar;
};
How was it? This time it was a simple flow, but as it gets more complicated, the difference from the case where functional I / F is not used becomes more noticeable. The advantage is that the amount of code is shortened, but when I actually introduce it, I feel that null checking is unnecessary, side effects are reduced by using functions, the scope is naturally reduced, and it is tested. I feel that it becomes simpler as a merit.
Recommended Posts