nantitv
nantitv

Reputation: 3733

create custom comparator in case of closure over variable

private Optional<Example> getTopExample(List<Example> exampleList, String input) {
String lowerCaseInput = input.toLowerCase();
Comparator<Example> exampleNearestMatchComparator = exampleComparator
                    .thenComparing((Example ex1, Example ex2) -> {
                        String name1LowerCase = getNameOfExample(ex1).toLowerCase();
                        String name2LowerCase = getNameOfExample(ex2).toLowerCase();
                        if (name1LowerCase.startsWith(input) && name2LowerCase.startsWith(lowerCaseInput)) {
                            return name1LowerCase.length() <= name2LowerCase.length() ? 1 : -1;
                        } else if (name1LowerCase.startsWith(lowerCaseInput)) {
                            return 1;
                        } else if (name2LowerCase.startsWith(lowerCaseInput)) {
                            return -1;
                        } else {
                            if (name1LowerCase.contains(lowerCaseInput) && name2LowerCase.contains(lowerCaseInput)) {
                                return name1LowerCase.length() <= name2LowerCase.length() ? 1 : -1;
                            } else if (name1LowerCase.contains(lowerCaseInput)) {
                                return 1;
                            } else if (name2LowerCase.contains(lowerCaseInput)) {
                                return -1;
                            } else {
                                return 1;
                            }
                        }
                    });
            return exampleList.stream())
                    .max(exampleNearestMatchComparator);
          }

I have a custom Object of type Example , which have properties like name, score etc... I would like to define a method whose purpose is to retrieve the top(mostImportant) Example from List of Example.

Example which has highest 'score' is the top(mostImportant) Example and I already have a comparator called 'exampleComparator' to do that purpose. In some cases, there is chance that two Example have the same score. In that case I would like to choose the Example whose name is nearly close to the 'input'. I created a 'exampleNearestMatchComparator' as you can see in the code.

As you can see, every time 'getTopExample' is invoked a new 'exampleNearestMatchComparator' will create. I would like to define 'exampleNearestMatchComparator' outside this method but as you can see 'exampleNearestMatchComparator' depends on a dynamic 'input' ( which can change on every invocation of getTopExample). As per my understanding, lambdas in streams are ' closed over values rather than variable' (http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html), I could not define 'exampleNearestMatchComparator' outside this method.

Am I correct? Any suggestions are welcome.

Upvotes: 0

Views: 39

Answers (1)

Malte Hartwig
Malte Hartwig

Reputation: 4555

If you want to prevent to re-create the nearest match comparator every time, you could make input, lowerCaseInput, and the comparator fields that you update before you use the comparator:

private Comparator<Example> exampleComparator             = // your comparator;
private String              input;
private String              lowerCaseInput;
private Comparator<Example> nearestMatchComparator        = // your lambda;
private Comparator<Example> exampleNearestMatchComparator = exampleComparator.thenComparing(nearestMatchComparator);

private Optional<Example> getTopExample(List<Example> exampleList, String input)
{
    this.input = input;
    this.lowerCaseInput = input.toLowerCase();
    return exampleList.stream().max(exampleNearestMatchComparator);
}

It might be nicer, though, to wrap the lambda into a separate class which has a setter for the input.

private Comparator<Example> exampleComparator             = // your comparator;
private Comparator<Example> nearestMatchComparator        = new NearestMatchComparator();
private Comparator<Example> exampleNearestMatchComparator = exampleComparator.thenComparing(nearestMatchComparator);

private Optional<Example> getTopExample(List<Example> exampleList, String input)
{
    nearestMatchComparator.setInput(input);
    return exampleList.stream().max(exampleNearestMatchComparator);
}

private final class NearestMatchComparator
    implements Comparator<Example>
{
    private String input;
    private String lowerCaseInput;

    public void setLowerCaseInput(String input)
    {
        this.input = input;
        this.lowerCaseInput = input.toLowerCase();
    }

    @Override
    public int compare(Example ex1, Example ex2)
    {
        // your implementation
    }
}

Upvotes: 1

Related Questions