Java: переменная «могла быть уже инициализирована», но я не понимаю, как

Сначала немного контекста: весь код, вставленный ниже, находится в другом классе, объявленном как открытый класс TheClass extends SomePrivateClass . Я не могу объявить эти классы в другом файле по разным причинам ... И сообщения журнала на французском языке. И я программист «окончательно счастливый». В чем суть проблемы ...

Теперь код ...(возможно, слишком много - удаление по запросу, чтобы сохранить только соответствующие части)

Пользовательское исключение:

private static final class BreadCrumbException
    extends Exception
{
    private BreadCrumbException(final String message)
    {
        super(message);
    }

    private BreadCrumbException(final String message, final Throwable cause)
    {
        super(message, cause);
    }
}

Перечисление для «материализации» видимости элемента хлебных крошек:

private enum Visibility
{
    MAINPAGE("R"),
    MENU("M"),
    BREADCRUMB("A"),
    COMMERCIAL("C");

    private static final Map reverseMap
        = new HashMap();

    private static final String characterClass;

    static {
        final StringBuilder sb = new StringBuilder("[");

        for (final Visibility v: values()) {
            reverseMap.put(v.flag, v);
            sb.append(v.flag);
        }

        sb.append("]");
        characterClass = sb.toString();
    }

    private final String flag;

    Visibility(final String flag)
    {
        this.flag = flag;
    }

    static EnumSet fromBC(final String element)
    {
        final EnumSet result = EnumSet.noneOf(Visibility.class);

        for (final String s: reverseMap.keySet())
            if (element.contains(s))
                result.add(reverseMap.get(s));

        return result;
    }


    static String asCharacterClass()
    {
        return characterClass;
    }

    static String asString(final EnumSet set)
    {
        final StringBuilder sb = new StringBuilder();

        for (final Visibility v: set)
            sb.append(v.flag);

        return sb.toString();
    }

    @Override
    public String toString()
    {
        return flag;
    }
}

Элемент хлебных крошек:

private static class BreadCrumbElement
{
    private static final Pattern p
        = Pattern.compile(String.format("(%s+)(\\d+)",
        Visibility.asCharacterClass()));

    private final String element;
    private final String menuID;
    private final EnumSet visibility;

    BreadCrumbElement(final String element)
    {
        final Matcher m = p.matcher(element);

        if (!m.matches())
            throw new IllegalArgumentException("Élément de fil d'ariane invalide: " + element);

        this.element = element;
        visibility = EnumSet.copyOf(Visibility.fromBC(m.group(1)));
        menuID = m.group(2);
    }

    public boolean visibleFrom(final Visibility v)
    {
        return visibility.contains(v);
    }

    @Override
    public boolean equals(final Object o)
    {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        final BreadCrumbElement that = (BreadCrumbElement) o;

        return element.equals(that.element);
    }

    @Override
    public int hashCode()
    {
        return element.hashCode();
    }

    @Override
    public String toString()
    {
        return element;
    }

    public String getMenuID()
    {
        return menuID;
    }
}

] Навигационная цепочка:

private static class BreadCrumb
    implements Iterable
{
    private static final BreadCrumb EMPTY = new BreadCrumb();

    private final List elements
        = new LinkedList();

    private String bc;

    BreadCrumb(final String bc)
        throws BreadCrumbException
    {
        final Set set = new HashSet();
        BreadCrumbElement e;

        for (final String element: bc.split("\\s+")) {
            e = new BreadCrumbElement(element);
            if (!set.add(e))
                throw new BreadCrumbException("Élément dupliqué "
                    + "dans le fil d'Ariane : " +  element);
            elements.add(e);
        }

        if (elements.isEmpty())
            throw new BreadCrumbException("Fil d'ariane vide!");

        if (!elements.get(0).visibleFrom(Visibility.MAINPAGE))
            throw new BreadCrumbException("Le fil d'Ariane ne "
                + "commence pas à l'accueil : " + bc);

        set.clear();
        this.bc = bc;
    }

    private BreadCrumb()
    {
    }

    BreadCrumb reverse()
    {
        final BreadCrumb ret = new BreadCrumb();
        ret.elements.addAll(elements);
        Collections.reverse(ret.elements);
        ret.bc = StringUtils.join(ret.elements, " ");
        return ret;
    }

    public Iterator iterator()
    {
        return elements.iterator();
    }

    @Override
    public String toString()
    {
        return bc;
    }
}

Интерфейс к рендереру хлебных крошек:

public interface BreadCrumbRender
{
    List getBreadCrumb()
        throws Throwable;

    String getTopCategory();

    String getMenuRoot();

    String getContext();
}

Реализация интерфейса выше, которая является источником моих проблем:

private class CategoryBreadCrumbRender
    implements BreadCrumbRender
{
    private final BreadCrumb bc;
    private final CTObject object;

    CategoryBreadCrumbRender(final CTObject object)
    {
        this.object = object;
        final String property;

        // FIELD_BC is declared as a private static final String earlier on.
        // logger is also a private static final Logger
        try {
            property = object.getProperty(FIELD_BC);
        } catch (Throwable throwable) {
            logger.fatal("Impossible d'obtenir le champ " + FIELD_BC
                + " de l'objet", throwable);
            bc = BreadCrumb.EMPTY;
            return;
        }

        try {
            bc = new BreadCrumb(property);
        } catch (BreadCrumbException e) {
            logger.fatal("Impossible d'obtenir le fil d'Ariane", e);
            bc = BreadCrumb.EMPTY; // <-- HERE
        }
    }
    // ....

В точке, отмеченной // выше, Intellij IDEA, которую я использую, и javac (1.6.0.29) говорят мне, что Переменная bc, возможно, уже была назначена на , что считается ошибкой (и действительно, код не компилируется) .

Проблема в том, что я не понимаю, почему ... Я рассуждаю так:

  • в первом блоке try / catch (и да, .getProperty () бросает Throwable), когда перехватывается исключение, bc назначается успешно, а затем я возвращаюсь, пока все хорошо;
  • во втором блоке try / catch конструктор может выйти из строя, и в этом случае я назначаю пустой хлебные крошки, поэтому все должно быть в порядке, даже если bc является окончательным: присваивание не происходит (?) в блоке try, а вместо этого происходит в блоке catch ...

Кроме нет, это нет. Поскольку и IDEA, и javac не согласны со мной, они, безусловно, правы. Но почему?

(а также BreadCrumb.EMPTY объявлен private static final в классе, интересно, почему я вообще могу получить к нему доступ ...Дополнительный вопрос)

РЕДАКТИРОВАТЬ : есть известная ошибка с ключевым словом final ( здесь , спасибо @MiladNaseri за ссылку на него), однако следует отметить что в этой ошибке переменная v всегда назначается только в блоках catch , но в приведенном выше коде я назначаю ее в блоках try и присваиваю только ее в catch блокируется, если возникает исключение. Также,Следует отметить, что ошибка возникает только во втором блоке catch .

5
задан fge 15 January 2012 в 02:24
поделиться