removeEldestEntry переопределение - PullRequest
3 голосов
/ 27 января 2011

Как я могу переопределить метод 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) в не может переопределить removeEldestEntry (java.util.Map.Entry) в java.util.LinkedHashMap;переопределенный метод не генерирует java.io.IOException

Без компилятора IOExecptio просит обработать IOexception и Filenotfoundexception.Может быть, существует другой способ?Пожалуйста, покажите мне пример кода, я новичок в Java и просто пытаюсь понять основные принципы 2-уровневого кэширования.Thx

Ответы [ 2 ]

3 голосов
/ 27 января 2011

Сначала необходимо убедиться, что ваш метод правильно переопределяет родительский. Вы можете внести небольшие изменения в сигнатуру, например, только выдать более конкретное проверенное исключение, которое является подклассом проверенного исключения, объявленного в родительском объекте. В этом случае родительский объект не объявляет ни одного проверенного исключения, поэтому вы не можете уточнить это дальше и не можете генерировать какие-либо проверенные исключения. Так что вам придется обрабатывать IOException локально. Есть несколько способов сделать это, преобразовать его в RuntimeException и / или зарегистрировать его.

Если вас беспокоит размер файла, вы, вероятно, не хотите сохранять только последнюю удаленную запись, но многие из них - поэтому вам следует открыть файл для добавления.

Вам нужно вернуть true из метода, чтобы фактически удалить старшего, и вам нужно решить, должен ли элемент быть удален.

При работе с файлами вы должны использовать try / finally, чтобы обеспечить закрытие ресурса, даже если есть исключение. Это может показаться немного уродливым - иногда приятно иметь вспомогательный метод для закрытия, так что вам не нужны дополнительные try / catch.

Как правило, вы также должны использовать некоторую буферизацию для файлового ввода-вывода, которая значительно повышает производительность; в этом случае используйте обтекание потока файла в 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 голос
/ 27 января 2011

Вы не можете изменить сигнатуру метода при переопределении метода. Поэтому вам нужно обработать исключение в переопределенном методе, а не бросать его.

Содержит хорошее объяснение того, как использовать try and catch: http://download.oracle.com/javase/tutorial/essential/exceptions/try.html

...