O que é encadeamento de exceção em Java | Manipulação de exceção
O que você entende por exceções encadeadas em Java?
O encadeamento de exceções , ou encapsulamento de exceções , é uma técnica de programação orientada a objetos para tratamento de exceções . O encadeamento de exceções ocorre quando uma exceção causa outra exceção. uma exceção encadeada é uma exceção causada por outra exceção. As exceções encadeadas são associadas de forma que a exceção anterior cause cada exceção na cadeia.
· Classe que pode ser lançada
· Usando exceções encadeadas
· Por que exceções encadeadas?
· Dificuldades com exceções encadeadas
· Programa
Classe arremessável
Construtores da classe Throwable que suportam exceções encadeadas em java:
- Throwable(Throwable cause) : - Onde cause é a exceção que causa a exceção atual.
- Throwable(String msg, Throwable cause) : - Onde msg é a mensagem de exceção e cause é a exceção que causa a exceção atual.
- método getCause() :- Este método retorna a causa real de uma exceção.
- Método initCause(Throwable cause) : - Este método define a causa para a exceção de chamada.
Freqüentemente, você deseja capturar uma exceção e lançar outra, mas ainda manter as informações sobre a exceção de origem — isso é chamado de encadeamento de exceções. A exceção original é a causa da segunda exceção. Assim, Chained Exceptions permite relacionar uma exceção com outra exceção, ou seja, uma exceção descreve a causa de outra exceção.
Antes do JDK 1.4, os programadores tinham que escrever seu próprio código para preservar as informações de exceção originais, mas agora todas as subclasses Throwable têm a opção de obter um objeto de causa em seu construtor. A causa deve ser a exceção de origem e, ao passá-la, você mantém o rastreamento de pilha de volta à sua origem, mesmo que esteja criando e lançando uma nova exceção.
O encadeamento de exceções também é chamado de agrupamento de exceções porque fazemos isso lançando novamente uma exceção capturada após envolvê-la em uma nova exceção. A exceção original é salva como uma propriedade (como cause ) da nova exceção.
Prática
try {
// creating an exception
NullPointerException e = new NullPointerException("Actual cause");
// wrapping the original exception in a new exception
ArithmeticException exc = new ArithmeticException("Apearent cause",e);
// throwing the exception
throw exc;
} catch(ArithmeticException e) {
// display top level exception (aprearent cause)
System.out.println("Caught: " + e);
// Getting the actual cause of the exception
System.out.println("Original cause: " + e.getCause());
}
}
Caught: java.lang.ArithmeticException: Apearent cause
Original cause: java.lang.NullPointerException: Actual cause
Por exemplo, considere um método que lança uma ArithmeticException devido a uma tentativa de divisão por zero, mas a causa real da exceção foi um erro de E/S que fez com que o divisor fosse zero. O método lançará a ArithmeticException para o chamador. O chamador não saberia sobre a causa real de uma exceção . Exceção encadeada é usada em tais situações.
É interessante observar que as únicas subclasses Throwable que fornecem o argumento de causa no construtor são as três classes de exceção fundamentais Error (usadas pela JVM para relatar erros do sistema), Exception e RuntimeException . Se você quiser encadear qualquer outro tipo de exceção, faça isso por meio do método initCause( ) em vez do construtor.
Exemplo
Aqui está um exemplo que ilustra a mecânica de lidar com exceções encadeadas:
// Demonstrate exception chaining.
class ChainExcDemo {
static void demoproc() {
// create an exception
NullPointerException e = new NullPointerException("top layer");
// add a cause
e.initCause(new ArithmeticException("cause"));
throw e;
}
public static void main(String args[]) {
try {
demoproc();
} catch (NullPointerException e) {
// display top level exception
System.out.println("Caught: " + e);
// display cause exception
System.out.println("Original cause: " + e.getCause());
}
}
}
Caught: java.lang.NullPointerException: top layer
Original cause: java.lang.ArithmeticException: cause
Exceções encadeadas podem ser levadas a qualquer profundidade necessária. Assim, a exceção de causa pode, ela própria, ter uma causa. Esteja ciente de que cadeias de exceções excessivamente longas podem indicar um projeto ruim.
Exceções encadeadas não são algo que todo programa precisará. No entanto, nos casos em que o conhecimento de uma causa subjacente é útil, eles oferecem uma solução elegante.
Por que exceções encadeadas?
O encadeamento de exceções permite mapear um tipo de exceção para outro, para que um método possa lançar exceções definidas no mesmo nível de abstração que o próprio método, sem descartar informações importantes de depuração.
Ou seja, se você tem um método que carrega algum objeto de um banco de dados, você pode preferir algum ResourceLoadException (mais próximo ao nível de abstração dos métodos) em vez de um SQLException de baixo nível , mesmo que essa seja a fonte original do problema. No entanto, se você simplesmente capturar a SQLException e lançar uma ResourceLoadException , poderá perder informações importantes sobre depuração.
Assim, encadear as exceções é uma boa alternativa. Você lança uma exceção de “alto nível”, adequada para o método específico, mas a encadeia com a exceção que a causou.
Precisamos encadear as exceções para tornar os logs legíveis. Vamos escrever dois exemplos. Primeiro sem encadear as exceções e segundo, com exceções encadeadas. Posteriormente, compararemos como os logs se comportam em ambos os casos.
Para começar, vamos criar uma série de Exceptions:
class NoLeaveGrantedException extends Exception {
public NoLeaveGrantedException(String message, Throwable cause) {
super(message, cause);
}
public NoLeaveGrantedException(String message) {
super(message);
}
}
class TeamLeadUpsetException extends Exception {
// Both Constructors
}
Vamos escrever um programa de exemplo sem encadear nossas exceções personalizadas.
public class MainClass {
public void main(String[] args) throws Exception {
getLeave();
}
void getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
e.printStackTrace();
throw new NoLeaveGrantedException("Leave not sanctioned.");
}
}
void howIsTeamLead() throws TeamLeadUpsetException {
throw new TeamLeadUpsetException("Team Lead Upset");
}
}
com.baeldung.chainedexception.exceptions.TeamLeadUpsetException:
Team lead Upset
at com.baeldung.chainedexception.exceptions.MainClass
.howIsTeamLead(MainClass.java:46)
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:34)
at com.baeldung.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Exception in thread "main" com.baeldung.chainedexception.exceptions.
NoLeaveGrantedException: Leave not sanctioned.
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:37)
at com.baeldung.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Em seguida, vamos escrever um exemplo encadeando nossas exceções personalizadas:
public class MainClass {
public void main(String[] args) throws Exception {
getLeave();
}
public getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
throw new NoLeaveGrantedException("Leave not sanctioned.", e);
}
}
public void howIsTeamLead() throws TeamLeadUpsetException {
throw new TeamLeadUpsetException("Team lead Upset.");
}
}
Exception in thread "main" com.baeldung.chainedexception.exceptions
.NoLeaveGrantedException: Leave not sanctioned.
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:36)
at com.baeldung.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Caused by: com.baeldung.chainedexception.exceptions
.TeamLeadUpsetException: Team lead Upset.
at com.baeldung.chainedexception.exceptions.MainClass
.howIsTeamLead(MainClass.java:44)
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:34)
... 1 more
Dificuldades com exceções encadeadas
Podemos usar o encadeamento de exceções em situações em que outra exceção causa uma exceção. No entanto, é importante observar que o encadeamento pode tornar nosso código mais difícil de ler e entender. Portanto, devemos usar o encadeamento de exceções com moderação e somente quando necessário.
Se usarmos exceções encadeadas, é uma boa ideia documentar a cadeia em nosso código. Isso ajudará outras pessoas a entender nosso código e facilitará a depuração se ocorrer um erro.
Programa
//: exceptions/DynamicFields.java
// A Class that dynamically adds fields to itself.
// Demonstrates exception chaining.
import static net.mindview.util.Print.*;
class DynamicFieldsException extends Exception {}
public class DynamicFields {
private Object[][] fields;
public DynamicFields(int initialSize) {
fields = new Object[initialSize][2];
for(int i = 0; i < initialSize; i++)
fields[i] = new Object[] { null, null };
}
public String toString() {
StringBuilder result = new StringBuilder();
for(Object[] obj : fields) {
result.append(obj[0]);
result.append(": ");
result.append(obj[1]);
result.append("\n");
}
return result.toString();
}
//...................hasField(String id)........................//
private int hasField(String id) {
for(int i = 0; i < fields.length; i++)
if(id.equals(fields[i][0]))
return i;
return -1;
}
//......................getFieldNumber(String id)....................//
private int getFieldNumber(String id) throws NoSuchFieldException {
int fieldNum = hasField(id);
if(fieldNum == -1)
throw new NoSuchFieldException();
return fieldNum;
}
//........................makeField(String id).....................//
private int makeField(String id) {
for(int i = 0; i < fields.length; i++)
if(fields[i][0] == null) {
fields[i][0] = id;
return i;
}
// No empty fields. Add one:
Object[][] tmp = new Object[fields.length + 1][2];
for(int i = 0; i < fields.length; i++)
tmp[i] = fields[i];
for(int i = fields.length; i < tmp.length; i++)
tmp[i] = new Object[] { null, null };
fields = tmp;
// Recursive call with expanded fields:
return makeField(id);
}
//.............................getField(String id).......................//
public Object getField(String id) throws NoSuchFieldException {
return fields[getFieldNumber(id)][1];
}
//.........................setField(String id, Object value)..........................
public Object setField(String id, Object value) throws DynamicFieldsException {
if(value == null) {
// Most exceptions don’t have a "cause" constructor.
// In these cases you must use initCause(),
// available in all Throwable subclasses.
DynamicFieldsException dfe = new DynamicFieldsException();
dfe.initCause(new NullPointerException());
throw dfe;
}
int fieldNumber = hasField(id);
if(fieldNumber == -1)
fieldNumber = makeField(id);
Object result = null;
try {
result = getField(id); // Get old value
} catch(NoSuchFieldException e) {
// Use constructor that takes "cause":
throw new RuntimeException(e);
}
fields[fieldNumber][1] = value;
return result;
}
// ......................main...................//
public static void main(String[] args) {
DynamicFields df = new DynamicFields(3);
print(df);
try {
df.setField("d", "A value for d");
df.setField("number", 47);
df.setField("number2", 48);
print(df);
df.setField("d", "A new value for d");
df.setField("number3", 11);
print("df: " + df);
print("df.getField(\"d\") : " + df.getField("d"));
Object field = df.setField("d", null); // Exception
} catch(NoSuchFieldException e) {
e.printStackTrace(System.out);
} catch(DynamicFieldsException e) {
e.printStackTrace(System.out);
}
}
}
null: null
null: null
null: null
d: A value for d
number: 47
number2: 48
df: d: A new value for d
number: 47
number2: 48
number3: 11
df.getField("d") : A new value for d
DynamicFieldsException
at DynamicFields.setField(DynamicFields.java:64)
at DynamicFields.main(DynamicFields.java:94)
Caused by: java.lang.NullPointerException
at DynamicFields.setField(DynamicFields.java:66)
... 1 more
*///:~
Como um valor de retorno, setField( ) também busca o valor antigo naquele local de campo usando getField( ) , que pode gerar uma NoSuchFieldException . Se o programador cliente chama getField( ) , então ele é responsável por lidar com NoSuchFieldException , mas se essa exceção for lançada dentro de setField( ) , é um erro de programação, então NoSuchFieldException é convertido em RuntimeException usando o construtor que recebe um argumento de causa.
Você notará que toString( ) usa um StringBuilder para criar seu resultado. Você aprenderá mais sobre StringBuilder no capítulo Strings, mas em geral você vai querer usá-lo sempre que estiver escrevendo um toString( ) que envolva loops, como é o caso aqui.
Bom aprendizado
Junte-se ao Grupo Mouad Oumous Java WhatsApp PARTICIPE
Junte-se ao canal de telegrama Mouad Oumous PARTICIPE
Apoie nossa publicação seguindo-a
Maximizando o potencial de sua equipe: como manter sua equipe de entrega de software ocupada Pergunta mais comum sobre entrevista baseada em fluxo Java8 — Parte final Como criar um projeto Quarkus simples com integração de banco de dados Lançando novamente uma exceção em Java | Lidando com exceções Eu ganho $ 300 escrevendo um livro em 2 dias - Veja como 10 maneiras simples, mas eficazes, de melhorar sua qualidade de vida




































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)