【问题标题】:removeEldestEntry overridingremoveEldestEntry 覆盖
【发布时间】:2011-01-27 15:17:44
【问题描述】:

如何覆盖 removeEldestEntry 方法以将最早的条目保存到文件?还有如何像我在 LinkedHashMap 中那样限制文件的大小。这是代码:

import java.util.*;

public class level1 {
private static final int max_cache = 50;
private Map cache = new LinkedHashMap(max_cache, .75F, true) {
protected boolean removeEldestEntry(Map.Entry eldest) {
    return size() > max_cache;
}
};


public level1() {
for (int i = 1; i < 52; i++) {
    String string = String.valueOf(i);
    cache.put(string, string);
    System.out.println("\rCache size = " + cache.size() +
                       "\tRecent value = " + i + " \tLast value = " +
                       cache.get(string) + "\tValues in cache=" +
                       cache.values());

}

我尝试使用 FileOutPutSTream :

    private Map cache = new LinkedHashMap(max_cache, .75F, true) {
    protected boolean removeEldestEntry(Map.Entry eldest) throws IOException {
        boolean removed = super.removeEldestEntry(eldest);
        if (removed) {
            FileOutputStream fos = new FileOutputStream("t.tmp");
            ObjectOutputStream oos = new ObjectOutputStream(fos);

            oos.writeObject(eldest.getValue());

            oos.close();
        }
        return removed;
    }

但是我得到了一个错误

Error(15,27): removeEldestEntry(java.util.Map.Entry) in 无法覆盖 java.util.LinkedHashMap 中的 removeEldestEntry(java.util.Map.Entry);被覆盖的方法不会抛出 java.io.IOException

如果没有 IOExecptio,编译器会要求处理 IOexception 和 Filenotfoundexception。 也许存在另一种方式?请给我看示例代码,我是 java 新手,只是想了解 2 级缓存的基本原理。谢谢

【问题讨论】:

  • 顺便说一句 super.removeEldestEntry(eldest) 总是返回 false。当您希望删除最旧的条目时,您必须覆盖它以返回 true。您的文件 t.tmp 将仅保存删除的最后一个条目。这是你想要的吗?

标签: java caching fileoutputstream linkedhashmap


【解决方案1】:

您首先需要确保您的方法正确地覆盖了父方法。您可以对签名进行一些小的更改,例如仅抛出更具体的已检查异常,该异常是在父项中声明的已检查异常的子类。在这种情况下,父级没有声明任何已检查的异常,因此您不能进一步细化它并且可能不会抛出任何已检查的异常。所以你必须在本地处理IOException。有几种方法可以做到这一点,将其转换为某种RuntimeException 和/或记录它。

如果您担心文件大小,您可能不想只保留最后删除的条目,而是保留其中的许多条目 - 因此您应该打开文件以进行追加。

您需要从方法中返回true 才能真正删除最旧的元素,并且您需要决定是否应该删除该元素。

在处理文件时,您应该使用 try/finally 来确保即使出现异常也关闭资源。这可能有点难看 - 有时最好有一个实用方法来执行关闭操作,这样您就不需要额外的 try/catch。

通常您还应该对文件 I/O 使用一些缓冲,这会大大提高性能;在这种情况下,使用将文件流包装在 java.io.BufferedOutputStream 中并将其提供给 ObjectOutputStream

这里有一些可以做你想做的事情:

private static final int MAX_ENTRIES_ALLOWED = 100;
private static final long MAX_FILE_SIZE = 1L * 1024 * 1024; // 1 MB

protected boolean removeEldestEntry(Map.Entry eldest) {
    if (size() <= MAX_ENTRIES_ALLOWED) {
        return false;
    }

    File objFile = new File("t.tmp");
    if (objFile.length() > MAX_FILE_SIZE) {
        // Do something here to manage the file size, such as renaming the file
        // You won't be able to easily remove an object from the file without a more
        // advanced file structure since you are writing arbitrary sized serialized
        // objects. You would need to do some kind of tagging of each entry or include
        // a record length before each one. Then you would have to scan and rebuild
        // a new file. You cannot easily just delete bytes earlier in the file without
        // even more advanced structures (like having an index, fixed size records and
        // free space lists, or even a database).
    }

    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(objFile, true); // Open for append
        ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos));

        oos.writeObject(eldest.getValue());
        oos.close(); // Close the object stream to flush remaining generated data (if any).
        return true;
    } catch (IOException e) {
        // Log error here or....
        throw new RuntimeException(e.getMessage(), e); // Convert to RuntimeException
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e2) {
                // Log failure - no need to throw though
            }
        }
    }
}

【讨论】:

  • 这就是我需要的!非常感谢!
【解决方案2】:

重写方法时不能更改方法签名。所以你需要在被覆盖的方法中处理异常而不是抛出它。

这包含一个关于如何使用 try and catch 的很好的解释: http://download.oracle.com/javase/tutorial/essential/exceptions/try.html

【讨论】:

  • +1 没错。就签名而言,您的新方法必须是现有方法的“插入式”替代品,这意味着从外部角度来看,它必须不抛出任何(已检查)异常。这通常会有点痛苦,我认为没有任何完全令人满意的通用方法可以克服这个问题。
猜你喜欢
  • 1970-01-01
  • 2011-06-11
  • 2012-01-28
  • 2012-02-16
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
  • 1970-01-01
  • 2020-06-06
相关资源
最近更新 更多