Alternative to new method to avoid duplicating code

Mark Sholund :

I would like to apply the same operations to different streams (using Java 8 at the moment)

Background: I am trying to get dimension data out of a Tika Metadata object

The following works but repeats code (metadata is a Tika Metadata object):

    private static void processDimensions(final Metadata metadata) {
        Optional<Integer> optWidth = Arrays.stream(new String[] {"tiff:ImageWidth", "Image Width"})
                .map(metadata::get)
                .filter(Objects::nonNull)
                .map(v -> v.replace("pixels", ""))
                .map(Integer::parseInt).findFirst();
        // do something with optWidth

        Optional<Integer> optHeight = Arrays.stream(new String[] {"tiff:ImageLength", "Image Height"})
                .map(metadata::get)
                .filter(Objects::nonNull)
                .map(v -> v.replace("pixels", ""))
                .map(Integer::parseInt).findFirst();
        // do something with optHeight
    }

I have gotten to this point which does not repeat code:

    private static void processDimensions(final Metadata metadata) {
        Optional<Integer> optWidth = processDimension(metadata, "tiff:ImageWidth", "Image Width");
        // do something with optWidth

        Optional<Integer> optHeight = processDimension(metadata, "tiff:ImageLength", "Image Height");
        // do something with optHeight
    }

    private static Optional<Integer> processDimension(final Metadata metadata, @NonNull final String... keys) {
        return Arrays.stream(keys).map(metadata::get).filter(Objects::nonNull).map(v -> v.replace("pixels", ""))
                .map(Integer::parseInt).findFirst();
    }

Is it possible to do this same thing without a separate method such as a Function inside processDimensions()? How would that look?

Ravindra Ranwala :

Yes declare it as a java.util.Function and reuse it.

Function<String[], OptionalInt> funct = keys -> Arrays.stream(keys)
    .map(metadata::get)
    .filter(Objects::nonNull)
    .map(v -> v.replace("pixels", ""))
    .mapToInt(Integer::parseInt)
    .findFirst();

Here's how you call it.

funct.apply(strArr);

In fact, declaring a method gives a much more readable name such as processDimensions and you declare parameter types with more descriptive names than a lambda, hence it is much more readable to me. Unless you are well versed with streams, you may find hard time reading this pipeline. Moreover, a method defines a de facto API, but a stream pipeline usually doesn't.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=3557&siteId=1