Najpierw szybko zmotywuję pytanie w moim przypadku użycia. Moja biblioteka musi ujawnić klasyfikator wyjątków Java do architektury, do której się podłącza. Na przykład:Cykle w przykutych wyjątkach
enum Classification { FATAL, TRANSIENT, UNKNOWN }
Classification classify(Throwable t) {
if (t instanceof MyTransientException)
return Classification.TRANSIENT;
else if (t instanceof MyFatalException)
return Classification.FATAL;
else
return Classification.UNKNOWN;
}
Czasem iz powodów z mojej kontroli, przeszły Wyjątkiem jest owinięcie się wokół jednego, który mnie interesuje, więc chcę, aby szukać łańcucha przyczynowo dla niego. Mój początkowy pomysł był następujący:
Classification classify(Throwable t) {
if (t == null)
return Classification.UNKNOWN;
if (t instanceof MyTransientException)
return Classification.TRANSIENT;
else if (t instanceof MyFatalException)
return Classification.FATAL;
else
return classify(t.getCause());
}
Niestety, może to doprowadzić do nieskończonej rekursji, jeżeli przeszedł wyjątek ma cykl w swoim łańcuchu przyczynowym. Jest bardzo mało prawdopodobne, że taki wyjątek zostanie przekazany, i można by argumentować, że jest to błąd w innym miejscu systemu, jeśli taki wyjątek jest tworzony, ale jestem bardzo niewygodny z powodu możliwości, że moja biblioteka będzie odpowiedzialna za produkcję awaria, jeśli tak się stanie. Interfejs API Throwble'a i javadoc nie zabraniają wyraźnie tej możliwości, wychodząc poza założenie, że cykle są z natury bezsensowne w łańcuchu przyczynowym.
Zauważyłem, że Guava ma metodę @Beta do wyodrębnienia łańcucha przyczynowego, Throwables.getCausalChain, ale jej implementacja jest podatna na ten sam problem - zakończy się rzuceniem OOME.
Mam zamiar użyć identity hash set do wykrycia cyklu i zmniejszenia ryzyka, ale chciałem usłyszeć, jak inni widzą ten problem. Myślisz, że jestem zbyt defensywny? Co byś zrobił?