首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >属性文件MRU缓存

属性文件MRU缓存
EN

Code Review用户
提问于 2015-08-12 18:17:04
回答 1查看 634关注 0票数 4

我尝试实现一个属性文件MRU缓存,其缓存大小有限,是最近使用的属性之一,只能保存在其中。此缓存中的读取缺失将导致对该特定属性的文件进行读取,并将其保存在缓存中,直到超出其他最近属性从该文件读入缓存的限制。

代码语言:javascript
复制
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedHashMap;

public class PropertiesFileMRUCache {

    private LinkedHashMap<String, String> propertiesMap = new LinkedHashMap<>(
            10);

    private int limit = 8;

    private String propertiesFile = "default.properties";

    public PropertiesFileMRUCache() {

    }

    public PropertiesFileMRUCache(String propertiesFile) {
        this.propertiesFile = propertiesFile;
    }

    public PropertiesFileMRUCache(int limit, String propertiesFile) {
        this(propertiesFile);
        this.limit = limit;
    }

    public String getCapital(String country) {
        String capital = propertiesMap.get(country);
        if (capital == null) {
            capital = readFromFile(country);
            if (propertiesMap.size() == limit) {
                propertiesMap.remove(propertiesMap.keySet().iterator().next());
            }
        } else {
            propertiesMap.remove(country);
        }
        propertiesMap.put(country, capital);
        return capital;
    }

    private String readFromFile(String country) {
        try (BufferedReader br = new BufferedReader(new FileReader(
                propertiesFile))) {
            for (String line; (line = br.readLine()) != null;) {
                if (line.startsWith(country)) {
                    return line.substring(line.indexOf('=') + 1);
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        PropertiesFileMRUCache pfc = new PropertiesFileMRUCache("res\\CountryCapital.properties");
        pfc.getCapital("India");
        pfc.getCapital("USA");
        pfc.getCapital("UK");
        pfc.getCapital("Kuwait");
        pfc.getCapital("Iraq");
        pfc.getCapital("Canada");
        pfc.getCapital("Australia");
        pfc.getCapital("India");
        pfc.getCapital("India");
        pfc.getCapital("India");
        pfc.getCapital("Germany");
        pfc.getCapital("India");
        pfc.getCapital("Germany");
        pfc.getCapital("China");
        pfc.getCapital("Pakistan");
        System.out.println(pfc.propertiesMap);
    }
}

出于测试目的,我提供了一个用户指定的属性为res\CountryCapital.properties,默认缓存限制为8。CountryCapital.properties的内容如下所示,以供参考:

德里India=New USA=Washington Egypt=Cairo Srilanka=Columbo Korea=Seoul Tailand=Bangkok Qutar=Doha Lebanon=Beirut Canada=Toronto Norway=Oslo Finland=Helsinki China=Beiging Japan=Tokyo Bangladesh=Dhaka Pakistan=Karachi Pakistan=Karachi Bangladesh=Dhaka Afganistan=Kabul Bangladesh=Dhaka Afganistan=Kabul en32 19 en32 21 en32 23 en32 25 en32

EN

回答 1

Code Review用户

发布于 2015-08-12 19:32:48

Java的LinkedHashMap代码虽然功能强大,但鲜为人知,它是为管理像您这样的缓存而构建的。在您的例子中,您应该使用访问顺序构造函数创建地图:

代码语言:javascript
复制
private static final class MyCache extends LinkedHashMap<String, String> {

    private final int limit;

    public MyCache(int limit) {
        super(limit, 0.75f, true);
        this.limit = limit;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
        return size() > limit;
    }
}

注意如何覆盖removeEldestEntry方法?

如果将所有这些放在一个应用程序中,它看起来如下:

代码语言:javascript
复制
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;


public class PropertiesFileMRUCache {
    private static final class MyCache extends LinkedHashMap<String, String> {

        private final int limit;

        public MyCache(int limit) {
            super(limit, 0.75f, true);
            this.limit = limit;
        }

        @Override
        protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
            return size() > limit;
        }
    }

    private final MyCache cache;

    private final Path propertiesFile;

    public PropertiesFileMRUCache(int limit, String file) {
        cache = new MyCache(limit);
        propertiesFile = Paths.get(file);
    }

    public String getCapital(String country) {
        return cache.computeIfAbsent(country, c -> readFromFile(c));
    }

    private String readFromFile(String country) {
        final String prefix = country + "=";
        try (Stream<String> lines = Files.lines(propertiesFile)){
            return lines.filter(line -> line.startsWith(prefix))
                    .map(line -> line.substring(prefix.length()))
                    .findFirst()
                    .orElse(null);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void main(String[] args) {
        PropertiesFileMRUCache pfc = new PropertiesFileMRUCache(8, "ccap.properties");
        pfc.getCapital("India");
        pfc.getCapital("USA");
        pfc.getCapital("UK");
        pfc.getCapital("Kuwait");
        pfc.getCapital("Iraq");
        pfc.getCapital("Canada");
        pfc.getCapital("Australia");
        pfc.getCapital("India");
        pfc.getCapital("India");
        pfc.getCapital("India");
        pfc.getCapital("Germany");
        pfc.getCapital("India");
        pfc.getCapital("Germany");
        pfc.getCapital("China");
        pfc.getCapital("Pakistan");
        System.out.println(pfc.cache);
    }
}

请注意,我是如何在您的readFromFile方法中进行黑客攻击的。我已经使它基于NIO2 2使用路径和文件。在Java 8中,这是最好的实践方法。我还流了行,我相信这会有所帮助。使用资源的尝试也能干净地关闭流。此外,computeIfAbsent是重用现有条目并创建缺失条目的正确方法。

有很多事情你应该认为是不同的。将LinkedHashMap的扩展视为最重要的,而改进computeIfAbsent的使用则是第二重要的。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/100721

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档