Help us understand the problem. What is going on with this article?

# Java8のSupplierで簡単キャッシュ

More than 3 years have passed since last update.

### (おさらい) 重い処理だからキャッシュ化したい

LargetObject.java
import java.util.List;

public class LargeObject {

private List<Integer> seq;

public List<Integer> getSeq() {
return seq;
}

public void setSeq(List<Integer> seq) {
this.seq = seq;
}

}

### Supplier を使って見る

Java8 で追加された java.util.function.Supplier<T> を使ってみます。今回は平均を求めたいだけなので Supplier<Double> ではなく DoubleSupplier を使いました。

AverageHelper.java
import java.util.List;
import java.util.function.DoubleSupplier;

public class AverageHelper {

private final DoubleSupplier averageSupplier;

public AverageHelper(final LargeObject largeObject) {
averageSupplier = new DoubleSupplier() {
private final double average = average(largeObject.getSeq());

@Override
public double getAsDouble() {
return average;
}

private double average(List<Integer> seq) {
System.out.println("calculating...");
return seq.stream().mapToInt(x -> x).average().getAsDouble();
}
};
}

public double calcAverage() {
System.out.println("average calculation");
return averageSupplier.getAsDouble();
}
}

AverageHelperTest.java
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;

public class AverageHelperTest {

@Test
public void testCalcAverage() {
List<Integer> seq = Arrays.asList(20, 12, 12);
LargeObject largeObject = new LargeObject();
largeObject.setSeq(seq);

AverageHelper target = new AverageHelper(largeObject);
Double actual = target.calcAverage();
Double expected = 44.0 / 3.0;

assertEquals(expected, actual);
target.calcAverage();
}
}

calculating...
average calculation
average calculation

### 欲しいタイミングで計算させる

AverageHelper2.java
import java.util.List;
import java.util.function.DoubleSupplier;

public class AverageHelper2 {

private final LargeObject largeObject;
private DoubleSupplier averageSupplier = () -> calculateAndCache();

public AverageHelper2(final LargeObject largeObject) {
this.largeObject = largeObject;
}

public double getAverage() {
System.out.println("get average");
return averageSupplier.getAsDouble();
}

private double calculateAndCache() {
if (!AverageFactory.class.isInstance(averageSupplier)) {
averageSupplier = new AverageFactory();
}
return averageSupplier.getAsDouble();
}

private class AverageFactory implements DoubleSupplier {
private final double average = average(largeObject.getSeq());

@Override
public double getAsDouble() {
return average;
}

private double average(List<Integer> seq) {
System.out.println("calculating...");
return seq.stream().mapToInt(x -> x).average().getAsDouble();
}
}
}

テストコードもちょっと修正して、実行してみます。

@Test
public void testCalcAverage2() {
List<Integer> seq = Arrays.asList(20, 12, 12);
LargeObject largeObject = new LargeObject();
largeObject.setSeq(seq);

AverageHelper2 target = new AverageHelper2(largeObject);
Double actual = target.getAverage();
Double expected = 44.0 / 3.0;

assertEquals(expected, actual);
target.getAverage();
}
get average
calculating...
get average

### 参考文献

Venkat Subramaniam『Javaによる関数型プログラミング』の6章『「遅延させる」ということ』を参考にさせていただきました。

Why do not you register as a user and use Qiita more conveniently?
1. We will deliver articles that match you
By following users and tags, you can catch up information on technical fields that you are interested in as a whole
2. you can read useful information later efficiently
By "stocking" the articles you like, you can search right away