Exceções e Loggers
Melhores Práticas
Quantos tipos de Exceções existem?
Checked
Unchecked
Exception
RuntimeException
Error
(checked)
(unchecked)
(unchecked)
Como usá-las?
Como tratá-las?
Lidando com exceções
public class ConnectionFactory {
public Connection create() throws SQLException {
return DriverManager.getConnection(
"jdbc:mysql://localhost:3306/bd"
"usuario", "senha");
}
}
public class FooDao {
public List<Foo> getAll() {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
// usando conn
}
}
que que precisamos fazer?
O mais fácil...
public class FooDao {
public List<Foo> getAll() throws SQLException {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
// usando conn
}
}
public class FooController {
private final FooService service;
private final Canvas canvas;
public void showFoo() {
try {
List<Foo> foos = service.getAll();
canvas.show(foos);
} catch (SQLException e) {
canvas.showText("Deu problema conectando com o banco!");
}
}
}
public class FooService {
private final FooDao dao;
public List<Foo> getAll() throw SQLException {
List<Foo> foos = dao.getAll();
System.out.println("Encontrou total de " + foos.size() + " foos");
return foos;
}
}
public class FooDao {
public List<Foo> getAll() throw SQLException {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
// usando conn
}
}
Checked Exception:
- Deixa claro os erros
- Obriga lidar com o erro
- Propaga até o infinito!
- Imcompatível com linguagem funcional
Não passamos a Checked Exception!
public class FooController {
private final FooService service;
private final Canvas canvas;
public void showFoo() {
List<Foo> foos = service.getAll();
canvas.show(foos);
}
}
public class FooService {
private final FooDao dao;
public List<Foo> getAll() {
List<Foo> foos = dao.getAll();
System.out.println("Encontrou total de " + foos.size() + " foos");
return foos;
}
}
public class FooDao {
public List<Foo> getAll() {
try {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
} catch (SQLException e) {
return null;
}
}
}
NullPointerException
public class FooController {
private final FooService service;
private final Canvas canvas;
public void showFoo() {
List<Foo> foos = service.getAll();
canvas.show(foos);
}
}
public class FooService {
private final FooDao dao;
public List<Foo> getAll() {
List<Foo> foos = dao.getAll();
System.out.println("Encontrou total de " + foos.size() + " foos");
return foos;
}
}
public class FooDao {
public List<Foo> getAll() {
try {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
} catch (SQLException e) {
return new ArrayList<>();
}
}
}
Mas e se nunca tá conectando no banco?
NUNCA ENGULA UMA EXCEÇÃO!
que fazemos então?
Problemas
- Não temos como nos recuperar
- Escondemos o problemas
- Não queremos jogar uma Checked Exception
como resolvemos?
public class DaoException extends RuntimeException {
// constructors
}
public class FooDao {
public List<Foo> getAll() {
try {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
} catch (SQLException e) {
throw new DaoException();
}
}
}
SEMPRE ADICIONE INFORMAÇÃO DO CONTEXTO!
public class FooDao {
public List<Foo> getAll() {
try {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
} catch (SQLException e) {
throw new DaoException("Não foi possível pegar todos os Foos do banco!", e);
}
}
}
Capture exceção quando
- Quer adicionar contexto a ela
public Foo findById(long id) {
try {
// logica
} catch (SQLException e) {
throw new DaoException("Problema ao pegar do banco Foo com id " + id, e);
}
}
Faça Wrap correto da Exceção
} catch (SQLException e) {
throw new DaoException("Problema no banco: " + e.getMessage());
}
} catch (SQLException e) {
throw new DaoException("Problema no banco: ", e);
}
Errado
Certo
public class FooController {
private final FooService service;
private final Canvas canvas;
public void showFoo() {
List<Foo> foos = service.getAll();
canvas.show(foos);
}
}
public class FooService {
private final FooDao dao;
public List<Foo> getAll() {
List<Foo> foos = dao.getAll();
System.out.println("Encontrou total de " + foos.size() + " foos");
return foos;
}
}
public class FooDao {
public List<Foo> getAll() {
try {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
} catch (SQLException e) {
throw new DaoException("Não foi possível pegar todos os Foos do banco!", e);
}
}
}
Não temos como lidar com a exceção
Último ponto antes de chegar no usuário
public class FooController {
private final FooService service;
private final Canvas canvas;
public void showFoo() {
try {
List<Foo> foos = service.getAll();
canvas.show(foos);
} catch (Throwable e) {
canvas.showText("Deu problema conectando com o banco!");
}
}
}
public class FooService {
// não podemos fazer nada sobre a exceção aqui!
}
public class FooDao {
public List<Foo> getAll() {
try {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
} catch (SQLException e) {
throw new DaoException("Não foi possível pegar todos os Foos do banco!", e);
}
}
}
Exception
RuntimeException
Throwable
Error
StackOverflow
OutOfMemory
public class FooController {
private final FooService service;
private final Canvas canvas;
public void showFoo() {
try {
List<Foo> foos = service.getAll();
canvas.show(foos);
} catch (Throwable e) {
canvas.showText("Deu problema conectando com o banco!");
}
}
}
public class FooService {
// não podemos fazer nada sobre a exceção aqui!
}
public class DaoException extends RuntimeException {
// constructors
}
public class FooDao {
public List<Foo> getAll() {
try {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
} catch (SQLException e) {
throw new DaoException("Não foi possível pegar todos os Foos do banco!", e);
}
}
}
NUNCA DÊ CATCH
EM THROWABLE!
public class FooController {
private final FooService service;
private final Canvas canvas;
public void showFoo() {
try {
List<Foo> foos = service.getAll();
canvas.show(foos);
} catch (Exception e) {
canvas.showText("Deu problema conectando com o banco!");
}
}
}
public class FooService {
// não podemos fazer nada sobre a exceção aqui!
}
public class DaoException extends RuntimeException {
// constructors
}
public class FooDao {
public List<Foo> getAll() {
try {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
} catch (SQLException e) {
throw new DaoException("Não foi possível pegar todos os Foos do banco!", e);
}
}
}
Só existe exception de banco?
SEJA ESPECÍFICO!
public class FooController {
private final FooService service;
private final Canvas canvas;
public void showFoo() {
try {
List<Foo> foos = service.getAll();
canvas.show(foos);
} catch (DaoException e) {
canvas.showText("Deu problema conectando com o banco!");
}
}
}
public class FooService {
// não podemos fazer nada sobre a exceção aqui!
}
public class DaoException extends RuntimeException {
// constructors
}
public class FooDao {
public List<Foo> getAll() {
try {
Connection conn = ConnectionFactory.create();
// código para carregar a lista de foo
} catch (SQLException e) {
throw new DaoException("Não foi possível pegar todos os Foos do banco!", e);
}
}
}
throw early
catch later
JOGUE EXCEÇÃO DA ONDE PROBLEMA OCORREU
RECUPERE ONDE PODES RESOLVER O PROBLEMA
Dos and Don'ts
Nunca jogue Exception e
use Log
} catch (SQLException e) {
LOGGER.error("Problema no banco!", e);
throw new DaoException(e);
}
Faça um ou o outro
Use bloco finally para garantir fechamento de recursos
public void fazAlgoCom(String arquivo) {
FileReader reader = null;
try {
reader = new FileReader(arquivo);
// do stuff
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {}
}
}
}
Nunca jogue Exceção de um bloco finally
public void fazAlgoCom(String arquivo) {
FileReader reader = null;
try {
reader = new FileReader(arquivo);
// do stuff
} finally {
if (reader != null) {
reader.close();
}
}
}
Exceção original ficará perdida
Resumito para lidar com Exceções
SÓ CAPTURE E JOGUE EXCEÇÃO...
Quer adicionar mais informação a exceção
Quer esconder implementação
} catch (HibernateException e) {
throw new DaoException("Nao foi possivel recuperar X do banco", e);
}
public void addUserFromFacebook(FbUser fbUser) {
User user = converter.convert(fbUser);
try {
dao.add(user);
} catch (DaoException e) {
throw new InvalidUserException("Não foi possível adicionar usuário " + user
+ " convertido do usuario do facebook " + fb, e);
}
}
CAPTURE E LIDE COM A EXCEÇÃO
Quando podes fazer algo sobre o problema
public void fazAlgoCom(String arquivo) {
FileReader reader = null;
try {
reader = new FileReader(arquivo);
// do stuff
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {}
}
}
}
use try/finally quando quer que algo seja feito mesmo que dê exceção
Mas e loggers?
Usando Logger
private static final Logger LOGGER = LoggerFactory.getLogger(X.class);
public void hello(String name) {
LOGGER.info("Hello {}", name);
}
nivel
param
valor
...
LOGGER.info("Store {} with id {} and shipping type {} just disappeared in thin air! O:",
store.getName(), store.getId(), store.getShipping().getType());
...
E se store for null?
LOGGER NÃO PODE SER PONTO DE FALHA
public class Store {
...
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("name", this.name)
.add("id", this.id)
.add("shipping", this.shipping)
.toString();
}
...
}
...
LOGGER.info("Store {} just disappeared in thin air! O:", store);
...
DEIXE O OBJETO SABER COMO SE IMPRIMIR!
public class UserService {
public User findUser(Long userId) {
try {
return userDao.findById(userId);
} catch (DaoException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
ALÉM DA LINHA, QUE INFORMAÇÃO TEMOS DO QUE ACONTECEU?
ADICIONA CONTEXTO AO LOGGER!
public class UserService {
public Optional<User> findUser(Long userId) {
try {
return userDao.findById(userId);
} catch (DaoException e) {
LOGGER.error("Houve problema ao tentar recuperar usuário com id {}",
userId, e);
}
}
}
2 parametros
1 argumento
se não adicionar argumento para um throwable, será impresso sua stacktrace!
e os níveis?
void update(User user) {
try {
userDao.update(user);
} catch (DatabaseException e) {
LOGGER.error("Could not update user {}", user, e);
}
}
INDICA FALHA!
ERROR
public void executeSearch(SearchOption searchOption, String query) {
switch (searchOption) {
case USER:
searchUser(query);
break;
default:
LOGGER.warn("Received unexpected search option! Option got: {}",
searchOption);
}
}
INDICA POSSÍVEL FALHA!
WARNING
...
List<Threshold> thresholdsExceeded = thresholds.getExceeded(metricSample);
for (Threshold thresholdExceeded : thresholdsExceeded) {
LOGGER.info("Metric Sample {} exceeded threshold {}",
metricSample, thresholdExceeded);
...
}
...
MUDANÇAS IMPORTANTES
INFO
...
LOGGER.DEBUG("Testing metric {} with thresholds {}", metricSample, thresholds);
List<Threshold> thresholdsExceeded = thresholds.getExceeded(metricSample);
for (Threshold thresholdExceeded : thresholdsExceeded) {
LOGGER.info("Metric Sample {} exceeded threshold {}",
metricSample, thresholdExceeded);
...
}
...
DEPURAÇÃO (DUH)
DEBUG
public PowerRanger choosePowerRangerToFight(Monster monster)
throws PowerRangerAvailabilityException {
LOGGER.trace("choosePowerRangerToFight(monster={})", monster);
for (PowerRanger ranger : alpha.getAvailablePowerRangers()) {
if (ranger.hasFightingPowerFor(monster)) {
LOGGER.trace("choosePowerRangerToFight(monster={}): {}",
monster, ranger);
return ranger;
}
}
throw new OnlyWeakPowerRangerAvailableException(monster);
}
DEPURAÇÃO (DUH)
+ detalhada
TRACE
DEVE APARECER SOMENTE EM DESENVOLVIMENTO!
Obrigado :)
exceções e loggers
By Caesar Ralf Franz Hoppen
exceções e loggers
- 1,467