删除最古老的条目覆盖

发布于 2024-10-14 17:58:58 字数 1549 浏览 5 评论 0原文

如何重写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;
    }

但我收到了错误

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

编译器要求处理 IOException 和 FilenotfoundException。 也许存在另一种方式?请向我展示示例代码,我是java新手,只是想了解二级缓存的基本原理。谢谢

How can I override removeEldestEntry method to saving eldest entry to file? Also how to limit the size of a file like I did it in LinkedHashMap. Here is code:

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());

}

I tried to use 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;
    }

But I have gained an error

Error(15,27): removeEldestEntry(java.util.Map.Entry) in cannot override removeEldestEntry(java.util.Map.Entry) in java.util.LinkedHashMap; overridden method does not throw java.io.IOException

Without IOExecptio compiler asks to handle IOexception and Filenotfoundexception.
Maybe another way exists? Pls show me example code, I am new in java and just trying to understand the basic principles of 2 level caching. Thx

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

本王不退位尔等都是臣 2024-10-21 17:58:58

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

You first need to make sure your method properly overrides the parent. You can make some small changes to the signature, such as only throwing a more specific checked exception that is a sub-class of a checked exception declared in the parent. In this case, the parent does not declare any checked exception so you can not refine that further and may not throw any checked exceptions. So you will have to handle the IOException locally. There are several ways you can do that, convert it to a RuntimeException of some kind and/or log it.

If you are concerned about the file size, you probably do not want to keep just the last removed entry but many of them - so you should open the file for append.

You need to return true from the method to actually remove the eldest and you need to decide if the element should be removed.

When working with files you should use try/finally to ensure that you close the resource even if there is an exception. This can get a little ugly - sometimes it's nice to have a utility method to do the close so you don't need the extra try/catch.

Generally you should also use some buffering for file I/O which greatly improves performance; in this case use wrap the file stream in a java.io.BufferedOutputStream and provide that to the ObjectOutputStream.

Here is something that may do what you want:

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
            }
        }
    }
}
许久 2024-10-21 17:58:58

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

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

You can't change the method signature when overriding a method. So you need to handle the exception in the overridden method instead of throwing it.

This contains a good explanation on how to use try and catch: http://download.oracle.com/javase/tutorial/essential/exceptions/try.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文