Analysis of Exception Handling Patterns in Java Projects

Transcription

Analysis of Exception Handling Patterns in Java Projects
Analysis of Exception Handling Patterns in Java Projects:
An Empirical Study
Suman Nakshatri, Maithri Hegde, Sahithi Thandra
David R. Cheriton School of Computer Science
University of Waterloo
Ontario, Canada
{sdnaksha, m2hegde, sthandra}@uwaterloo.ca
ABSTRACT
Exception handling is a powerful tool provided by many programming languages to help developers deal with unforeseen
conditions. Java is one of the few programming languages
to enforce an additional compilation check on certain subclasses of the Exception class through Checked Exceptions.
This enforcement has made the writing of exception handling code very common. Almost all the existing IDEs today give the suggestions and even generate the try-catch
code automatically to assist the developers. This motivated
us to study the habits of developers in general. As part
of this study, empirical data was extracted from software
projects developed in Java. The intent is to explore how
developers respond to checked exceptions and identify common patterns used by them to deal with exceptions, checked
or otherwise. Bloch’s book - “E↵ective Java” [1] was used
as reference for best practices in exception handling - these
recommendations were compared against results from the
empirical data. Also, results of GitHub and SourceForge
projects are compared for their similarities and di↵erences.
Results of this study indicate that most programmers ignore
checked exceptions and leave them unnoticed. Additionally,
it is observed that classes higher in the exception class hierarchy are more frequently used as compared to specific
exception subclasses. The paper also describes a potential
solution to handling exceptions compiled from Bloch’s book
and Bruce’s blog on exception handling. This explains the
usage of custom exceptions and how they can lead to cleaner
and scalable code.
CCS Concepts
•Software and its engineering ! Error handling and
recovery;
Keywords
Java Exception Handling; Github; Best Practices; Boa
Permission to make digital or hard copies of all or part of this work for personal or
classroom use is granted without fee provided that copies are not made or distributed
for profit or commercial advantage and that copies bear this notice and the full citation on the first page. Copyrights for components of this work owned by others than
ACM must be honored. Abstracting with credit is permitted. To copy otherwise, or republish, to post on servers or to redistribute to lists, requires prior specific permission
and/or a fee. Request permissions from [email protected].
MSR’ 16, 14-15 May 2016, Austin, TX, USA
c 2016 ACM. ISBN 123-4567-24-567/08/06. . . $15.00
DOI: 10.475/123 4
Table 1: Dataset Statistics for GitHub
Total projects
7,830,023
Number of Java projects
554,864
Methods with atleast one catch block 10,862,172
Total number of Catch blocks
16,172,462
Table 2: Dataset Statistics for SourceForge
Total projects
699,331
Number of Java projects
50,692
Methods with atleast one catch block 6,657,595
Total number of Catch blocks
9,956,760
1.
INTRODUCTION
An exception is an unanticipated or an exceptional (as
the name suggests) occurrence that may arise during the
execution of a program, disrupting its normal flow. Exception handling is a proactive mechanism to respond to such
an event in a sound and reliable manner. This concept was
originated with Lisp programming language in the 1960s,
where return value of the ‘ERRSET’ keyword was used to
determine error scenarios. Many programming languages
subsequently o↵ered built-in support for exception handling.
Some languages, for example C, use return codes to handle
exceptions. However, one amongst many disadvantages of
this mechanism is the use of multiple flow control statements
to return respective error codes, thereby making the code
verbose and difficult to maintain. This resulted in newer
approaches to handling errors.
Java provides a powerful support system for exceptions
involving dedicated try-catch-finally blocks to separate functional code from exception-handling logic. Throwable is the
superclass of all exceptions and errors (which are unhandled
critical problems). In this paper, the focus is exclusively on
exceptions. The terms error(s) and exception(s) are used
interchangeably, however in all cases they refer to exceptions and not the category of serious errors, unless specified
otherwise.
One noted advantage of exception handling in Java is its
hierarchy and classification of exception types based on the
type of error. The highest in this hierarchy is the class Exception. All subclasses of Exception which do not fall under
RuntimeException are categorized as checked exceptions.
The term checked has come into usage as Java enforces or
checks for these exceptions during compilation. The intention is to force developers to think of sophisticated ways to
Figure 1: Boa script to find top unaccompanied
method calls in a checked exception block.
handle such exceptions in case they occur. In this paper, we
mine data to gain insight into how developers handle checked
exceptions and the utility of Java enforcing the same. An
extension to this study includes extracting general exception
handling patterns used by developers.
Furthermore, the specificity of an error caught increases as
we move down the class hierarchy. To illustrate, the exception SQLClientInfoException inherits properties of its parent class SQLException. Catching an SQLClientInfoException would provide extra information of the error to a developer by fetching details regarding SQL client properties,
going beyond what is provided by superclass SQLException.
Since each exception is a Java object, an exception thrown
at a lower level can also be caught by its superclass. In
this paper, we explore the frequency and usage of generic
exceptions. The research questions that guide our work are:
1. How well are checked exceptions handled? Does Java
enforcing them fulfill its purpose?
2. What scenarios are exception handling used for?
3. How often are top-level exceptions caught and their
potential danger(s) to the product quality?
2.
RELATED WORK
Exception handling behavior is a topic of long term study
by software engineering researchers and product managers.
Shah et al.[7] studied the developer perspective on exception
handling and attempted to understand the root cause for developer attitude and actions. The study was conducted by
observing and interviewing nine Java developers - eight of
whom were interns at a large multinational organization,
and the last participant was a full-time employee at the
same organization. The participants were asked questions
that evaluated their understanding and approach towards
exception handling. The results showed that most participants seemed to give a low priority to exception handling as
a task, or included exceptions in their code only when the
language forced them to handle checked exceptions. The
basis of our study is to support or negate these qualitative
claims with empirical data.
Monperrus et al.[5] compared best practices fetched from
known and authentic sources against empirical data extracted
from Java projects. While this was an empirical study, the
dataset used was small (32 Java projects). Moreover, the focus was not to specify patterns used in exception handling,
but to challenge or validate known best practices. For example, they picked code snippets from the analysed projects
to showcase that empty catch blocks were not always harmful as suggested in the knowledge sources. The contribution
of our study, on the other hand, is in producing empirical
data fetched from a large scale data source, with the intent
of identifying common practices followed by developers to
tackle exceptions.
Understanding that exception handling is taken as a last
priority in any software developement process causing software project failures, Rogerio et. all [2] provide a systematic
approach to handling exceptions. The main idea of their
study is proposing a solution in which exceptions are identified and their handlers are defined as a part of the software
development process, and not put o↵ till the end. They suggest an approach to define and divide exception class types
based on the software system model analysed, thus categorizing them into application-related, design-related and
implementataion-related exceptions.
Xie and Thummalapenta[8] have tried to address the issue
of poor exception handling behaviour exhibited by developers by creating formal specifications of exceptions. They
represent expected exception-handling behaviour in the form
of sequence association rules and exceptional cases as alternative patterns. These rules and patterns are meant to be
used by tools to automatically analyze exception handling
behaviour as a future work.
3.
RESEARCH METHODOLOGY
Analysis data was extracted from MSR’16 Mining Challenge Boa Dataset[3] using the BOA domain specific language[3] run on their web interface[6]. This dataset contains metadata for almost 700,000 SourceForge (SF) and
8,000,000 GitHub (GH) repositories. Fig. 1 gives a sample
Boa script written to extract data for top checked exceptions. The latest snapshot was picked up for the purpose
of this study and a total of 554,864 Java projects in the
GitHub repository were analyzed. The dataset is current as
of September 2015. A study on 50,692 Java projects from
the SourceForge Sep’ 13 dataset was also performed to validate GitHub results. Table 1 and 2 give brief statistics on
both datasets studied. However, being a larger and more
current dataset, our results are more concentrated towards
GitHub.
The Boa programming language is composed of di↵erent
domain-specific constructs which make it particularly useful for mining language features. These constructs include
Table 3: Top Exceptions Caught in Catch Blocks.
ExceptionType Number Checked Exception Unchecked Exception
Exception 3,859,217
Superclass
Superclass
IOException 2,170,519
Yes
SQLException
681,638
Yes
Throwable
670,214
Superclass
Superclass
InterruptedException
555,555
Yes
IllegalArgumentException
460,872
Yes
NumberFormatException
364,362
Yes
NullPointerException
326,193
Yes
RemoteException
263,920
Yes
RecognitionException
203,892
Yes
TOTAL
3,671,632
1,355,319
software abstractions like CodeRepository, Revision, Project,
Statement etc., which can be used as part of queries to the
dataset. Boa’s infrastructure obtains the source code of files
in the SourceForge and GitHub repositories and parses the
source code to obtain its abstract syntax tree(AST) representation. Each Boa program is designed to traverse through
the AST of the target projects to reach the required query
object. Considering the extremely large number of projects
in the repositories, Boa programs run on a distributed cluster to reduce execution time. Developers are given the choice
of selecting a small, medium or complete subset of the repositories on which to run the query. Direct access is not given
to the source code of the files in the Boa dataset. All research questions which needed to observe real code snippets
have been answered by obtaining the full path of the required file from Boa, and manually traversing the file to the
required code.
3.1
Mining Exception Categories
The number of exceptions handled in a method can be extracted using one or any combination of the following three
methods:
1. Exceptions thrown using throws keyword in the method
signature.
2. Exceptions thrown using throw keyword in the method
body.
3. Exceptions caught in a try catch block of a method.
The first method might not provide a true picture of real
life scenarios, as exceptions thrown using throws in the method
signature are falsely added with the call stack of methods
propagating the exception until it is caught. Furthermore,
an exception thrown using the second method will eventually be caught by a caller method using a try catch block.
Hence, the top twelve exceptions caught in catch blocks, as
shown in Table 3, are chosen for our study. For each exception in the top twelve above, both long and short notations
were considered - for eg., the long notation for IOException
would be java.io.IOException.
4.
Figure 2: Top Operations performed in Checked Exception catch blocks (GH).
RESULTS
The cumulative results in Table 3 show that checked exceptions account for almost three times the number of unchecked exceptions in Java projects. This can be attributed
to the compile-time checking for the presence of checked exception handlers.
In the following sections, mined results on the usefulness of
checked exceptions are presented. Further insights into: how
programmers handle said exceptions; value of enforcement,
and general exception handling patterns are provided.
It can be inferred from the above table that developers often catch exceptions at the ‘top-level’ using the Throwable
and Exception class. Further details about this implementation strategy and potential harmful e↵ects to code quality
are discussed in Section 4.3.
4.1
Analyzing Checked Exception Handling
As discussed above, Java enforces the compile-time use of
checked exceptions. For example, while making a database
connection, it raises a compilation error forcing the developer to handle SQLException. This also compels one to
envision any possible errors that could occur and tackle
them as desired. For example, if one expects a primary
server crash, the catch clause could be coded to connect to
a secondary server or return an appropriate message back to
client. This enforcement is designed to make the application
developer life easier and the code quality better.
Usage of the top three checked exceptions picked from Table 3 was analyzed. This began with mining the top twenty
method calls; throw an exception calls and variable declarations made inside a catch construct of a checked exception,
as shown in Fig. 2. It can be observed that the top spot
Figure 3: Code Snippet from a GitHub project.
is shared between printStrackTrace and log methods, which
indicates that many developers use checked exceptions for
logging and debugging. The second major observation is
the large number of empty catch blocks - this is discussed
in Section 4.2.
However, the operations shown in Fig. 2 may have accompanied other operations inside the catch block. For example,
a log call may have been made along with a throw exception call. For additional clarity, results for common unaccompanied operations performed inside a checked exception
handling construct, as shown in Fig. 4, were mined. The
phrase “unaccompanied operation” implies that operation in
the figure was the only action taken inside the catch block.
It can be noted that 83% of the printStackTrace operations
were performed unaccompanied. Many developers use popular IDEs such as Eclipse and IntelliJ which provide powerful suggestion and code completion tools, including adding
try catch constructs with default printStackTrace call for
checked exceptions. Fig. 3 gives an example of a code snippet extracted from the GitHub project “pennshare”, which
shows the checked SQLException handling.The high number of printStackTrace calls reveals that a lot of developers
ignore and leave the catch block unattended. Bloch asserts
[1]-“To capture the failure, the detail message of an exception should contain the values of all parameters and fields
that contributed to the exception.” For instance, in the code
snippet in Fig. 3, instead of using the generic printStackTrace, handling the SQLException by printing out the details of the SQLState of the database and the error code
specific to the vendor would give more useful information to
the developer and help in faster debugging of the issue.
Another interesting observation in Fig. 4 and Fig. 5 is the
significant number of System.out.println statements that are
the sole statements inside catch blocks of checked exceptions.
It is recommended that a catch block should contain a comment explaining why a particular catch block is left unattended, at the very least. Though we do not have access to
the source code of data, it is safe to assume that developers
use System.out.println statements to print useful information that might help them later on for debugging purposes.
Since the access to plain source code is not provided, it may
be difficult to interpret the reasons for developers using variable declarations inside catch blocks.
We performed a compare and contrast of GitHub results
with data extracted from SourceForge projects. The results from SourceForge showcase a similar trend with 78%
printstacktrace and 67% log statements made unaccompanied. This is shown in Fig. 5.
Furthermore, it is also noticed that developers tend to
Figure 4: Comparison of top unaccompanied operations performed vs their total instances in catch
blocks of checked exceptions (GH).
Figure 5: Comparison of top unaccompanied operations performed vs their total instances in catch
blocks of checked exceptions (SF).
wrap checked exceptions inside unchecked ones while throwing them back to the caller. Due to lack of access to plain
source code, we may not be able to judge the reason behind these wrapped throws. However, Bloch recommends in
his book [1] to “use checked exceptions for recoverable conditions and runtime exceptions for programming errors”. It
states that if the user finds a checked exception unrecoverable, wrapping into an unchecked exception keeping the
stack trace intact and throwing it back to the client or the
caller method is justifiable. The data indicates that around
74% of throw statements in IOException handlers and 65%
of throw statements in SQLException handlers were made to
RuntimeException, which is consistent with Bloch’s views.
This leads us to answer our first research question. Though
checked exceptions were introduced to direct the thought
process towards error recovery, the results show that most
developers neglect handling them well. This defeats the purpose of the Java enforcement mechanism.
4.2
Analyzing General Exception Handling
The data related to checked exceptions noted in Section
4.1 seems to extrapolate well with all types of exceptions.
In this section, we will focus more on general exception handling patterns.
Figure 6: Code Snippet from a GitHub project
demonstrating an empty catch block.
Figure 7: Top operations used in exception handling
(GH).
Java has a well-built, self-sufficient exception handling library. Bloch ”favors the use of standard exceptions” which
already provide great level of specificity and information.
This is because developing applications/APIs using standard exceptions allow novice developers or developers who
are new to a project or exception handling understand APIs
more clearly, thereby eliminating the confusion typically caused
by custom exceptions. As shown in Table 3, the top 10 exceptions being used are all standard exceptions. This observation shows that the above-mentioned recommendation is
being followed widely.
The number of empty catch blocks in Fig. 7 draws attention. The percentage of empty blocks was calculated with
respect to the total number of catch blocks present in the
dataset. It was found that 20% of the total (16,172,462)
catch blocks were left empty. The fact that one in every
five catch blocks is left empty stresses the need for a better
understanding of the use of exception handling. As stated
by Bloch “An empty catch block defeats the purpose of exceptions, which is to force you to handle exceptional conditions”. This holds the product at risk for the following
reasons: time consuming debugging due to absence of tracing and logging when an error occurs; and swallowing issues
not intended to be caught, which results in false positive
output[1]. An example of a catch block being left empty
is shown in Fig. 6. This has been taken from the project
Ghostrec35 in the GitHub repository, and demonstrates how
the code is vulnerable to bugs arising because of the empty
NullPointerException handler.
The top method calls in catch constructs show significantly more number of logging techniques as compared to
the ones found in previous section. These include: log4j/
slf4j methods at all five levels (info, debug, etc.); handler
module methods such as ReportError; logger module methods at various levels (severe, warning, etc.). All these method
calls made for logging were added to produce the final number shown in Fig. 7 for ‘Log Statements’.
Fig. 7, Fig. 8 and Fig. 10 show a high usage of logging
inside catch constructs; in particular, of log messages being
used as standalone actions. This supports the claim in paper
[7] - “developers have shifted their perspective on exception
handling from the intended proactive approach (i.e., how to
handle possible exceptions) to a reactive approach (i.e., using
exception handling as debugging aids)”. The printStackTrace
number also backs this claim.
Bloch advises that “higher layers should catch lower-level
exceptions and, in their place, throw exceptions that can be
explained in terms of the higher-level abstraction”[1]. To
study this scenario, top hundred throw calls were extracted
in the form of ‘A -> B’ where A/B are exception class
types and A throws B in its handler. As shown in the Table
4, the highest number of translations (145,916) were made
from Exception to RuntimeException which runs counter to
Bloch’s advice. Most conversions from any exception type
were made to RuntimeException. Excluding the above number and looking at next top twenty results, 66% conversion
from lower to higher level exception and 24% from higher
to lower are observed. The remaining were thrown at the
same level, for eg. ‘IOException throws IOException’. This
allows them to add a layer of abstraction and hide the inner
implementation details, also allowing them to let the caller
method know of an unrecoverable event, which can eventually be handled up the stack. These results show positive
alignment with the advice.
A total of 3832 instances of return NULL in GitHub and
3479 instances in SourceForge were also observed in catch
blocks. Since the number of such observations is small (relative to the dataset) and the reason behind the action is
unknown - this does not stand out as a major concern. The
use of customized exceptions in Java projects could not be
analyzed due to the size of the dataset and have been excluded from the scope of this study.
From the above, we see that many developers seem to use
Java exception handling for logging and fetching the stack
trace. Many more developers choose to leave the catch constructs empty. Quite a lot of them convert and throw back
exceptions to their caller methods. Due to the size of the
dataset, it was challenging to fetch user-defined exceptions
and meaningful operations performed as they are specific to
each project. This answers our second research question.
4.3
Catching Top-level or Generic Exceptions
As showcased in Table 3, data of the top twenty exceptions
caught shows that the superclass of all exceptions viz. Exception has the largest frequency of occurrence and that its
base class Throwable also has a surprisingly high usage. As
per findings in [7], many developers tend to keep exception
handling as simple as possible, which potentially encourages
Table 4: Top 15 ‘A -> B’ calls made inside a catch construct (GH).
A -> B Expression
Number of Throws
Exception -> RuntimeException
145,916
IOException -> RuntimeException
120,586
TException -> IOException
30,504
Exception -> IOException
22,851
Exception -> SystemException
20,230
Exception -> IllegalArgumentException
19,435
Exception -> Exception
17,818
InterruptedException -> RuntimeException
17,791
UnsupportedEncodingException -> RuntimeException
17,724
Throwable -> RuntimeException
17,507
SQLException -> RuntimeException
16,949
IllegalAccessException -> RuntimeException
16,252
HibernateException -> SystemException
16,154
RemoteException -> RuntimeException
15,332
IOException -> IllegalStateException
15,122
Figure 8: Comparison of top unaccompanied operations performed vs their total instances in Exception
handling (GH).
Figure 9: Comparison of number of instances of
methods that caught only Exception or Throwable
classes vs the total number of instances of methods
with only catch block
Figure 10: Comparison of top unaccompanied operations performed vs their total instances in Exception handling (SF).
wrapping of the calling code in a single Exception or Throwable class handler.
The numbers in Table 3 for Exception and Throwable includes code wrapped in multiple handlers along with generic
handlers. To learn more, the number of methods that contained only Exception and Throwable handlers was analyzed
further. A staggering 78% of the methods that caught Exception did not catch any of its subclasses and a similar
observation of 84% was made for Throwable. A total of
10,862,172 methods with catch clauses were extracted. 30%
of them contained only the generic Exception class handler.
Exception handling increases the burden on JVM in that
the code wrapped in try-catch blocks often takes more time
to execute when compared to the plain code. Nevertheless, good use of this mechanism pays o↵ significantly by
saving the precious time of developers from painful debugging. So, just the catching of top level Exceptions is not
very helpful. Here we analyze the ratio of the number of
methods with only one catch block in them to the number
of the methods with only one catch block catching top level
exceptions, namely, Exception and Throwable, as shown in
the Fig. 9. We found that nearly 37% (3,023,506 out of
8,107,881) of methods have caught only Exception whereas
Figure 11: Top operations in Exception catch construct (GH).
7% (564,723 out of 8,107,881) of methods have caught only
Throwable in the GitHub repository. This observation shows
us that developers often don’t make good use of the Exception handling mechanism. A similar observation was made
in SourceForge data as well.
Bloch [1] maintains that - “Exception handlers that are
too general can make code more error-prone by catching and
handling exceptions that were not anticipated by the programmer and for which the handler was not intended”. As
shown in Fig. 11, printing stack trace and logging were
the top actions executed in an Exception catch construct.
This makes the code more vulnerable as generic handlers
provide low scope for specific log messages and recovery actions. Throwable handlers place a higher risk on the product
as they also capture critical errors, which are not meant to
be caught as exceptions. This reveals a dismal picture of the
code and product quality.
Finally, answering our third and last research question,
Exception is the leading handler used, followed shortly by
Throwable. Reiterating Bloch’s views[1], this practice places
a higher risk on the final product by catching unrelated bugs
and discouraging specific meaningful recovery.
5.
DISCUSSION
In this section, views from Bloch’s book [1] have been
summarized which briefly mention the best practices to be
followed in handling exceptions. We extend those views to
discuss one particular method which Bruce Eckel, the author of the book “Thinking in Java” recommends as a good
practice for handling exceptions in a Java project. This uses
custom exceptions.
5.1
Best Practices
In his book [1], Bloch mentions the following points which
a developer must keep in mind while dealing with exceptions:
1. “Use exceptions only for exceptional scenarios” - This
suggests that exception handling must not be used as a
flow control technique or as a part of for- or while- loop
ending logic. Quite a bit of JVM resources are used up
in handling an exception. Hence, using exception handling for non exceptional scenarios not only confuses
the end user of the method regarding its purpose, it
also leads to performance degradation.
2. “Use checked exceptions for recoverable conditions and
Figure 12: Custom Request Failure Exception.
runtime exceptions for programming errors” - This has
been discussed in Section 4.1.
3. “Avoid unnecessary use of checked exceptions” - This
suggests to use checked exceptions only when the exception cannot be avoided by properly coding the API
and there is no alternate recovery step that could be
taken in case the said exception occurs.
4. “Favor the use of standard exceptions” - Since Java already has an extensive exception handling API, using
standard exceptions makes the code more understandable and achieves code reusability.
5. “Throw exceptions appropriate to the abstraction” - This
has been discussed in Section 4.2.
6. “Document all exceptions thrown by each method” While writing Javadocs and like, developers must remember to document the exceptions thrown by each
method, along with the reason for throwing such an
exception so as to make it clear to the calling API.
7. “Include failure-capture information in detail messages”
- This suggests to capture value and parameters that
caused the exception, especially while throwing back
an exception. This makes exception tracking easier.
8. “Don’t ignore exceptions” - This has been discussed in
Section 4.2.
5.2
Using Custom Exceptions
Bruce Eckel, described and recommended in his blog [4],
one of the ways to use custom exceptions to handle exceptions, which we describe below.
Re-emphasizing Bloch’s [1] point 7 above, all exceptions
thrown by a method must be documented in its Javadoc,
so that the calling API is well aware of their presence. In
case of many exceptions being handled, the calling API will
need to ensure catching all those exceptions. In case the
method is changed later and the exceptions caught in it are
also changed, all the APIs using the method need to be
refactored to maintain proper functioning. To avoid these
scenarios, custom exceptions prove as a good bet here.
Consider the code constructs given in Fig. 12 and Fig. 13
wherein one has two types of custom exceptions, RequestFailureException and ApplicationFailureException. The former catches any exceptions related to the client request, for
Figure 13: Custom Application Failure Exception.
eg. wrong filename input, while the latter catches any exceptions related to application failure, for eg. database server
crash. When a callee method encounters an exception and is
unable to process any steps to recover from it, it throws the
custom exception back based on the exception type that occurred. The caller method in turn would not have to worry
about the multiple exceptions that were caught in the callee
method and only needs to catch either or both of the two
custom exceptions.
Both these custom exceptions are coded to wrap the original exception that occurred and to return the original exception when needed. The advantage here is that when the
custom exception is coded to return back the original exception that was caught, it facilitates abstraction while not
holding back information on the real exception and its parameters. Fig. 14 shows how exceptions could be wrapped
in custom exceptions and thrown back to the caller. Fig.
15 showcases the use of the custom exceptions defined. It
illustrates how the custom exception could be re-thrown to
fetch the original exceptions, hence giving specificity and
customization of exception handling.
Since each caller in the call stacktrace does not need to
catch all exceptions thrown in the callee method, it makes
the code much cleaner. Furthermore, any changes made with
respect to exception handling like adding or deleting some
exception handlers will not a↵ect the caller API, making the
code more scalable.
6.
Figure 14: Sample code illustrating throwing custom exceptions.
7.
Figure 15: Sample Code illustrating use of Custom
Exception picked from Bruce’s blog [4].
THREATS TO VALIDITY
The material extracted from the data set provides empirical results on the exception types, number of exceptions
and actions taken within a catch construct. However, due
to lack of access to raw source code, the rationale behind
these actions is unknown. Hence, our reasoning behind how
and why handlers were used and categorizing them as incorrect may not always be sound. Also, the usage of custom exceptions could not be evaluated as custom exception
names di↵er with each project. Considering the volume of
the projects studied, picking such exceptions proved costly
and hence were removed from the scope of this paper. Since
the intent of the study has been to align with best practices
stated by Bloch[1], the focus here has been to surface patterns which stand for or against those views supported by
empirical data.
CONCLUSION
In this paper, we studied all Java projects in the GitHub
and SourceForge repositories to spot common exception handling practices. We have particularly analyzed the checked
exception handling in good detail. Next, these observations
were compared against best practices presented by Bloch[1].
To sum up the results, most developers ignore checked exceptions and leave them unattended. This is true for other
types of exceptions as well. General exception handling
shows developer inclination shifting from proactive recovery
to debugging.
The ignore-for-now and mere logging approach followed
for checked exceptions may help with debugging, but the
absence of required recovery steps and continued smooth
flow may lead to errors going unnoticed and potential incorrect product output. Thus, handling exceptions well is
a skill that developers need to inculcate in themselves, else
this language enforcement of checked exception handling will
fall short of its intended value. Developers also tend to use
generic handlers over specific ones. The reason for these
approaches cannot be confirmed to be correct or incorrect
without studying source codes. However overall, the results
show major di↵erences between theoretical best practices
and the use of exception handling in practice. We further
summarized the best practices stated by Bloch and described
one of the recommended approaches by Bruce to tackle exceptions.
8.
REFERENCES
[1] J. Bloch. E↵ective Java (2Nd Edition) (The Java
Series). Prentice Hall PTR, Upper Saddle River, NJ,
USA, 2 edition, 2008.
[2] R. de Lemos and A. Romanovsky. Exception handling
in the software lifecycle. International Journal of
Computer Systems Science and Engineering,
16(2):167–181, March 2001.
[3] R. Dyer, H. A. Nguyen, H. Rajan, and T. N. Nguyen.
Boa: A language and infrastructure for analyzing
ultra-large-scale software repositories. In Proceedings of
the 35th International Conference on Software
Engineering, ICSE’13, pages 422–431, 2013.
[4] B. Eckel. Does java need checked exceptions?
http://www.mindview.net/Etc/Discussions/
CheckedExceptions/, 2005.
[5] M. Monperrus, M. Germain De Montauzan, B. Cornu,
R. Marvie, and R. Rouvoy. Challenging Analytical
Knowledge On Exception-Handling: An Empirical
Study of 32 Java Software Packages. Technical report,
Laboratoire d’Informatique Fondamentale de Lille,
2014.
[6] H. Rajan, T. N. Nguyen, R. Dyer, and H. A. Nguyen.
Boa website. http://boa.cs.iastate.edu/, 2015.
[7] H. Shah, C. Görg, and M. J. Harrold. Why do
developers neglect exception handling? In Proceedings
of the 4th International Workshop on Exception
Handling, WEH ’08, pages 62–68, New York, NY, USA,
2008. ACM.
[8] T. Xie and S. Thummalapenta. Making exceptions on
exception handling, 2012.