Refactoring scoring algorithm I have the following code which I feel that I must refactor, but not sure how to do it.

List&lt;AlgoTuningData&gt; feedbackScoreDatas;
List&lt;AlgoTuningData&gt; topRatedDatas;
int score1 = 0;
int score2 = 0;
boolean matched1 = false;
boolean matched2 = false;
for (AlgoTuningData topRatedData : topRatedDatas) {
    if (!matched1 &amp;&amp; isMatchesTopRatedTuning(p1, topRatedData)) {
        score1 += topRatedData.getRank();
        matched1 = true;
    }

    if (!matched2 &amp;&amp; isMatchesTopRatedTuning(p2, topRatedData)) {
        score2 += topRatedData.getRank();
        matched2 = true;
    }

    if (matched1 &amp;&amp; matched2)
        break;
}

matched1 = false;
matched2 = false;
for (AlgoTuningData feedbackScoreData : feedbackScoreDatas) {
    if (!matched1 &amp;&amp; isMatchesFeedbackScoreTuning(p1, feedbackScoreData))           {
        score1 += feedbackScoreData.getRank();
        matched1 = true;
    }
    if (!matched2 &amp;&amp; isMatchesFeedbackScoreTuning(p2, feedbackScoreData)) {
        score2 += feedbackScoreData.getRank();
        matched2 = true;
    }

      if (matched1 &amp;&amp; matched2)
      break;
}

private boolean isMatchesTopRatedTuning(Product product, AlgoTuningData topRatedData) {
        return product.getIsTopRated().equals(topRatedData.getValue());
    }

private boolean isMatchesFeedbackScoreTuning(Product product, AlgoTuningData feedbackScoreData) {
        return product.getPrice() &lt;= feedbackScoreData.getMaxProductPrice();
    }


As you can see, I have 2 lists. each list has a different type of boolean function that verifies its objects. Each call to the function increases the score1 and score2.

I thought to use Callable, but wasn't sure how to do it for a list of items.

I would like my code to have one-line call for each List&lt;AlgoTuningData&gt;, something like this:

increaseScore(List&lt;Integer&gt; scores, List&lt;AlgoTuningData&gt;, myFunc)
I would not refactor this substantially, except maybe to avoid the reuse of the matched1 and matched2 variables:

{
    boolean matched1 = false;
    boolean matched2 = false;
    for (...) {
        ...
    }
}

// and here again


Your intuition is correct that this could be done much cleaner using functional programming, but FP is a pain with Java 1–7. So we have the following options:


use Java 8
use functional language like Scala
ignore the pain, and do it anyway


The last solution does not involve java.util.concurrent.Callable, but an interface of our own:

interface TuningDataTest {
    boolean test(Product product, AlgoTuningData datum);
}


We can then write a function scoreTuningData:

private static class Score {
    final public int score1;
    final public int score2;

    public Score(int s1, int s2) {
        score1 = s1;
        score2 = s2;
    } 

    public Score add(Score that) {
        return new Score(this.score1 + that.score1, this.score2 + that.score2);
    }
}

private Score scoreTuningData(Product p1, Product p2, Iterable&lt;AlgoTuningData&gt; data, TuningDataTest test) {
    boolean matched1 = false;
    boolean matched2 = false;
    int score1 = 0;
    int score2 = 0;

    for (AlgoTuningData datum : data) {
        if (!matched1 &amp;&amp; test.test(p1, datum)) {
            matched1 = true;
            score1 += datum.getRank();
        }
        if (!matched2 &amp;&amp; test.test(p2, datum)) {
            matched2 = true;
            score2 += datum.getRank();
        }
        if (matched1 &amp;&amp; matched2) {
            break;
        }
    }

    return new Score(score1, score2);
}


Note that “data” is the plural form of “datum”, the word “datas” does not exist. One “datum” is a “record”, “data” are a set of records.

And your main code would then look like:

List&lt;AlgoTuningData&gt; topRatedData = ...;
List&lt;AlgoTuningData&gt; feedbackScoreData = ...;
Score score = scoreTuningData(p1, p2, topRatedData, new TuningDataTest() {
    @Override
    public boolean test(Product product, AlgoTuningData datum) {
        return product.getIsTopRated().equals(datum.getValue());
    }
}).add(scoreTuningData(p1, p2, feedbackScoreData, new TuningDataTest() {
    @Override
    public boolean test(Product product, AlgoTuningData datum) {
        return product.getPrice() &lt;= datum.getMaxProductPrice();
    }
}));

int score1 = score.score1;
int score2 = score.score2;