Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performing same operation on multiple functions

I have a class with multiple get functions such as getF1 to getF10. I want, for each of these getters, to replace the letter "x" to an "a" (random example). The getter can return a null value.

So far, this is what I have done and it works, is there a way to get something better looking than this?

public void foo(final MyObject bar) {
    Optional.of(bar).map(MyObject::getF1).ifPresent(s -> bar.setF1(s.replaceAll("x", "a"));
    Optional.of(bar).map(MyObject::getF2).ifPresent(s -> bar.setF2(s.replaceAll("x", "a")));
    ...
    Optional.of(bar).map(MyObject::getF10).ifPresent(s -> bar.setF10(s.replaceAll("x", "a")));
}

I was thinking of something like this, using a list, obviously, this code is wrong but you get the idea:

public void foo(final MyObject bar) {
    List<Function> func = new ArrayList<Function>();
    func.addAll(Arrays.asList(MyObject::getF1, MyObject::getF2, ..., MyObject::getF10));
    Optional.of(bar).map(func).ifPresent(s -> func(s.replaceAll("x", "a"));
}

Maybe working with a stream could get the job done?

Thanks!

like image 639
lopoto Avatar asked Apr 06 '26 23:04

lopoto


1 Answers

You can store the mappers used in Optional::map and consumers used in Optional::ifPresent in a Map.

I also recommend you to create a method to avoid the code duplication for the String replacement which shall be called easily. This is useful since all the replacements are the same

private String replaced(String string) {
    return string.replaceAll("x", "a");
}

Then simply iterate over the entries and apply each of the key-value pairs (the order doesn't matter):

Map<Function<? super MyObject, ? extends String>, Consumer<? super String>> map = new HashMap<>();
map.put(MyObject::getF1, bar::setF1);
map.put(MyObject::getF2, bar::setF2);
map.put(MyObject::getF10, bar::setF10);
// ...

map.forEach((function, consumer) -> {
        Optional.of(bar).map(function).map(this::replaced).ifPresent(consumer);
});

If you want to extend this mechanism and apply a different function to each String passed to the setter, then you need also to use a different structure:

public final class Mapping {

    private final Function<MyObject, String> getterFunction;
    private final Function<String, String> transformationFunction;
    private final Consumer<String> setterFunction;

    public Mapping(final Function<MyObject, String> getterFunction, final Function<String, String> transformationFunction,
        final Consumer<String> setterFunction) {
        this.getterFunction = getterFunction;
        this.transformationFunction = transformationFunction;
        this.setterFunction = setterFunction;
    }

    // getters
}

And the usage is similar (the transformation functions are samples and might vary):

List<Mapping> list = new ArrayList<>();
list.add(new Mapping(MyObject::getF1, s -> s.replaceAll("x", "a"), bar::setF1));
list.add(new Mapping(MyObject::getF2, s -> s.replaceAll("x", "a"), bar::setF2));
list.add(new Mapping(MyObject::getF10, s -> s.replaceAll("x", "a"), bar::setF10));

list.forEach(mapping -> {
    Optional.of(bar)
            .map(mapping.getGtterFunction)
            .map(mapping.getTransformationFunction)
            .ifPresent(mapping.getSetterFunction);
});
like image 144
Nikolas Charalambidis Avatar answered Apr 08 '26 13:04

Nikolas Charalambidis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!