2011-01-27 13 views
3

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

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; 
    } 

但我已经获得了一个错误

错误(15,27):removeEldestEntry(java.util.Map .Entry)in不能覆盖java.util.LinkedHashMap中的removeEldestEntry(java.util.Map.Entry);重写的方法不会抛出java.io.IOException

没有IOExecptio编译器要求处理IOexception和Filenotfoundexception。 也许有另一种方式存在?请告诉我示例代码,我是java中的新成员,并试图理解2级缓存的基本原理。 Thx

+0

BTW super.removeEldestEntry(长子)始终返回false。当您想要最老的条目被丢弃时,您必须覆盖它以返回true。您的文件t.tmp只会保留最后一个被删除的条目。这是你的意图吗? – 2011-01-27 15:49:47

回答

3

首先,您需要确保你的方法正确地重写了父。您可以对签名进行一些小的更改,例如只抛出一个更具体的检查异常,该异常是在父级中声明的检查异常的子类。在这种情况下,父类不会声明任何检查的异常,因此您无法进一步细化,并且可能不会抛出任何检查的异常。所以你必须在本地处理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 
      } 
     } 
    } 
} 
+1

那就是我需要的!非常感谢! – BraginiNI 2011-01-27 21:42:05

1

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

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

+0

+1正确。你的新方法在签名方面必须是现有方法的“插入式”替换,这意味着从外部角度来看,它不得抛出任何(检查过的)例外。这往往有点痛苦,我不认为有任何完全令人满意的通用方法来克服这一点。 – 2011-01-27 15:23:41