Сначала немного контекста: весь код, вставленный ниже, находится в другом классе, объявленном как открытый класс 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, возможно, уже была назначена на
, что считается ошибкой (и действительно, код не компилируется) .
Проблема в том, что я не понимаю, почему ... Я рассуждаю так:
.getProperty ()
бросает Throwable), когда перехватывается исключение, bc
назначается успешно, а затем я возвращаюсь, пока все хорошо; bc
является окончательным: присваивание не происходит (?) в блоке try, а вместо этого происходит в блоке catch ... Кроме нет, это нет. Поскольку и IDEA, и javac не согласны со мной, они, безусловно, правы. Но почему?
(а также BreadCrumb.EMPTY
объявлен private static final
в классе, интересно, почему я вообще могу получить к нему доступ ...Дополнительный вопрос)
РЕДАКТИРОВАТЬ : есть известная ошибка с ключевым словом final
( здесь , спасибо @MiladNaseri за ссылку на него), однако следует отметить что в этой ошибке переменная v
всегда назначается только в блоках catch
, но в приведенном выше коде я назначаю ее в блоках try
и присваиваю только ее в catch
блокируется, если возникает исключение. Также,Следует отметить, что ошибка возникает только во втором блоке catch
.