Exception_Handling_A_Field_Study_in_Java_and_NET
Exception_Handling_A_Field_Study_in_Java_and_NET
net/publication/221496451
CITATIONS READS
122 4,832
2 authors:
All content following this page was uploaded by Bruno Cabral on 29 May 2014.
1 Introduction
2 Related Work
Since the pioneering work of John B. Goodenough in the definition of a notation for
exception handling [2] and Flaviu Cristian in defining its usage [3], the programming
language constructs for handling and recovering from exceptions have not changed
much. Nevertheless, programming languages designers have always suggested
different approaches for implementing these mechanisms.
Several studies have been conducted over the years for validating the options taken
in each different implementation. For instance, Alessandro Garcia, et al. did a
comparative study on exception handling (EH) mechanisms available developing
dependable software [4]. Alessandro’s work consisted in a survey of exception
handling approaches in twelve object-oriented languages. Each programming
language was analyzed in respect to ten technical aspects associated with EH
constructs: exception representation; external exceptions in signatures; separation
between internal and external exceptions; attachment of handlers to program
constructs (e.g. to statements, objects, methods, etc.); dynamism of handler binding;
propagation of exceptions ; continuation of the flow control (resumption or
termination); clean-up actions; reliability checks; and concurrent exception handling.
After the evaluation of all the programming languages in terms of exception
mechanisms, the major conclusion of the study was that “none of the existing
exception mechanisms has so far followed appropriate design criteria” and
programming language designers are not paying enough attention to properly
supporting error handling in programming languages.
Saurabh Sinha and Mary Jean Harrold performed an extensive analysis of
programs with exception handling constructs and discussed their effects on analysis
techniques such as control flow, data flow, and control dependence [5]. In the
analysis, the authors also presented techniques to create intraprocedural and
interprocedural representations of Java programs that contain EH constructs and an
algorithm for computing control dependences in their presence. Using that work, the
authors performed several studies and showed that 8.1% of the methods analyzed
used some kind of exception mechanism and that these constructs had an important
influence in control-dependence analysis.
R. Miller and A. Tripathi identified several problems in exception handling
mechanisms for Object-Oriented software development [6]. In their work, it is shown
that the requirements of exception handling often conflict with some of the goals of
object-oriented designs, such as supporting design evolution, functional
specialization, and abstraction for implementation transparency. Being specific:
object-oriented programming does not support a complete exception specification
(extra information may be needed for the exception context not supported by an
object interface); state transitions are not always atomic in exception handling;
exception information needs to be specific, but functions can be overloaded to have a
different meaning in different situations; the exception handling control flow path is
different from the normal execution path and is up to the programmer to differentiate
both of them. Thus, the modification of object-oriented frameworks for adaptation to
exception handling can have the following effects in terms of: Abstraction, change of
abstraction levels and the usage of partial states; Encapsulation, the exception context
may leak information that reveals or allows the access to the exception signaler
private data; Modularity, design evolution may be inhibited by exception
conformance; Inheritance anomalies may occur when a language does not support
exception handling augmentation in a modular way.
Martin P. Robillard and Gail C. Murphy in their article on how to design “robust
Java programs with exceptions”, classified exceptions as a global design problem and
discussed the complexity of exception structures [7]. In their work, the authors
pointed that the lack of information about how to design and implement with
exceptions lead to complex and spaghetti-like exception handling code. The main
factors that contribute to the difficulty of designing exception structures are the global
flow of exceptions and the emergence of unanticipated exceptions. To help control
these factors, the authors refined an existent software compartmenting technique for
exception design and report about its usage in the rewriting of three Java programs
and the consequent improvements they observed.
More recently, due to a new AOP approach to EH, two interesting studies were
published emphasizing the separation of concerns in error handling code writing
[8][9]. Martin Lippert and Cristina Lopes rewrote a Java application using AspectJ.
Their objective was to provide a clear separation between the development of
business code and exception handling code. This was achieved by applying error
handling code as an advice (in AOP terminology) [10]. With this approach they also
obtained a large reduction in the amount of exception handling code present in the
application. Some of the results presented show that without aspects, the amount of
code for exceptions is almost 11% of all the code; with aspects it represents only
2.9%. Lippert’s paper also accounts the total number of catch blocks in the code and
the most common exception classes used as parameters for these catch statements.
One of the measures they present to support their AOP approach is the reduction of
the number of different handlers effectively written for each one of the most
commonly used exception classes. For the top 5 classes were implemented between
90.0% and 96.5% less handlers. F. Filho and C. Rubira conducted a similar study but
they were not so enthusiastic in their results. The authors presented four metrics to
evaluate the AOP approach to exception handling: separation of concerns; coupling
between components and depth of inheritance tree; cohesion in the access to fields by
pairs of method and advice; and dimension (size and number) of code. The work
reports that the improvements of using AOP do not represent a substantial gain in any
of the presented metrics showing that reusing handlers is much more difficult than is
usually advertised. Handler reuse depends of the type of exceptions being handled, on
what the handler does, the amount of contextual information needed; and what the
method raising the exception returns and what the throws clause actually specifies.
The objective of this study is different from its predecessors. It does not target the
quality of the mechanisms available in programming languages but the usage that
programmers make of them. The emphasis is on understanding how programmers
write exception handling code, how much of the code of an application is dedicated to
error recovery and identifying possible flaws in their usage.
3 Workbench
The target platforms of this study were the .NET and Java environments, as well as
the C# and Java programming languages.
Selecting a set of applications for the study was quite important. The code present in
the applications had to be representative of common programming practices on the
target platforms. Also, care had to be taken so that these would be “real world”
applications developed for production use (i.e. not simply prototypes or beta
versions). This was so in order not to bias the results towards immature applications
where much less care with error handling exists. Finally, in order to be possible to
perform different types of analyses, both the source code and the binaries of the
applications had to be available.
Globally, we analyzed 32 applications divided into two sub-sets of 16 .NET
programs and 16 Java programs. Each one of these sub-sets was organized in four
categories accordingly to their nature:
• Libraries: software libraries providing a specific application-domain API.
• Applications running on servers (Server-Apps): Servlets, JSPs, ASPs
and related classes.
• Servers: server programs.
• Stand-alone applications: desktop programs.
PhotoRoom
albums
ASP.NET webmail application that is written
SharpWebMail
in C#
.NET
Berkeley DB
engine
ERP software application with integrated
Compiere
CRM solutions
Stand-alone
4 Methodology
The test applications were analyzed at source code level (C# and Java sources) and at
binary level (metadata and bytecode/IL code) using different processes.
To perform the source code analysis two parsers were generated using antlr [11],
for C#, and javacc [12] for Java. These parsers were then modified to extract all the
exception handling code into one text file per application. These files were then
manually examined to build reports about the content of exception handlers.
The source code of all application was examined with one exception. Due to the
huge size of Mono, only its “corlib” module was processed.
The parsers were also used to identify and collect information about try blocks
inside loops (i.e. detect try statements inside while and do..while loops). This is so
because normally this type of operations corresponds to retrying a block of code that
has raised an exception in order to recover from an abnormal situation.
The main objective of this article is to understand how programmers use the
exception handling mechanisms available in programming languages. Nevertheless,
the analysis of the applications source code is not enough by itself when trying to
distinguish between the exceptions that the programmer wants to handle and the
exceptions that might occur at runtime. This is so because the generated IL
code/bytecode can produce more (and different) exceptions than the ones that are
declared in the applications source code by means of throw and throws
statements.
To perform the analysis of the .NET assemblies and of the Java class files two
different applications were developed: one for .NET and another for Java. The first
one used the RAIL assembly instrumentation library [13] to access assembly metadata
and IL code and extract all the information about possible method exceptions,
exception handlers and exception protection blocks. The second application targeted
the Java platform and used the Javassist bytecode engineering library [14] to read
class files and extract exception handler information.
All data was stored on a relational database for easy statistical treatment.
Table 2. List of Assemblies and Java Packages analyzed.
.NET Java
Meebey.SmartIrc4net.dll ThoughRiverCommons (all)
Reports.dll Javolution (all)
mscorlib.dll JoSQL (all)
NLog.dll org.manentia.kasai
rq.dll (UserStory) Exoplatform (all)
PhotoRoom.dll GoogleTagLibrary (all)
SharpWebMail.dll XPlanner (all)
SushiWiki.dll Mobile platform (all)
Brettle.Web.NeatUpload.dll JBoss (all)
Perspective.dll org.apache
nhost.exe JCGrid (all)
DCSharpHub.exe Berkeley DB (all)
nunit.core.dll org.compiere
SharpDevelop.exe net.sf.jftp
Ascgen dotNET.exe org.columba
SqlBuddy.exe org.eclipse
For each application only one file (.NET) or package (and sub-packages) of classes
(Java) was analyzed. Table 2 shows the names of the files and packages that were
used in this study. The criterion followed to select these targets was the size of the
files and their relevance in the implementation of the application core.
5 Results
In the following subsections we will present the results of this study, drawing some
observations about their significance.
Nevertheless, we should caution that although the number of applications that were
used was relatively large (32), it is not possible to generalize the observations to the
whole .NET/Java universe. For that, it would be necessary to have a very significant
number of applications, possible consisting in hundreds programs. Even so, due to the
care taken in selecting the target applications, we believe that the results allow a
relevant glimpse into current common programming practices in exception handling.
One important metric for understanding current error handling practices is the
percentage of source code that is used in that task. For gathering this metric, we
compared the number of lines of code inside all catch and finally handlers to the total
number of lines of the program. The results are shown in Figure 1.
It is quite visible that in Java there is more code dedicated to error handling than in
.NET. This difference can be explained by the fact that in Java it is compulsory to
handle or declare all exceptions a method may throw, thus increasing the total amount
of code used for error handling. Curiously, there is an exception to this pattern. In the
Server Application group, the difference is almost non-existent. To explain this result
we examined the applications’ source code. For this class of applications, both in Java
and .NET, programmers wrote quite similar code. Meaning that they expect the same
kind of errors (e.g. database connections loss, communication problems, missing data,
etc.) and they use the same kind of treatment (the most common handler action in this
type of applications is logging the error).
8,00%
7,05%
7,00%
5,99%
6,00%
5,00%
Java
4,00%
.NET
3,36% 3,33% 3,43%
3,11%
3,00%
2,23%
2,00% 1,62%
1,00%
0,00%
Libraries Server Apps Servers Stand-Alone
One surprising result is that the total amount of code dedicated to exception
handling is much less than what would be expected. This is even more surprising in
Java where using exceptions is almost mandatory even in small programs. Our results
show that the maximum amount of code used for error handling was 7% in the
Servers group. Overall, the result is 5% for Java, with a 2% standard deviation, and
3% for .NET, with a standard deviation of 1%. It should be noted the applications
used in this study are quite mature, being widely used. We reason that the effort
dedicated to writing error protection mechanisms is not as high as expected, even for
highly critical applications like servers. The forceful of declaring and catching
checked exceptions in Java effectively increases (almost doubles) the amount of error
handling code written, even though it is still represents a small fraction of all the code
of an application. The critical issue is that normally error handling code is being used
more to alert the user, to abort the applications or to force them to continue their
execution, than to actually recover from existing errors.
5.2 Code in Exception Handlers
Apart from measuring the amount of the code that deals with errors, to find out how
programmers use exception handling mechanisms, it is important to know what kind
of actions are performed when an error occurs.
To be able to report on this subject we had to inspect sets of ten thousand lines of
application source code. As a matter of fact, we covered all the handlers (catch and
finally) in all the applications except for JBoss and Eclipse. For these two, due to their
dimension, only 10% of the 96,405 lines of code existing inside of exception handlers
were examined. Even so, they are representative of the rest.
Category Description
The handler is empty, is has no code and
Empty
does nothing more than cleaning the stack
Some kind of error logging or user
Log
notification is carried out
In the event of an error or in the execution of
Alternative/
a finally block some kind of pre-determined
Static
(alternative) object state configuration is
Configuration
used
A new object is created and thrown or the
Throw
existing exception is re-thrown
The protected block is inside a loop and the
Continue handler forces it to abandon the current
iteration and start a new one
The handler forces the method in execution
to return or the application to exit. If the
Return
handler is inside a loop, a break action is also
assumed to belong to this category
The handler performs a rollback of the
modifications performed inside the protected
Rollback
block or resets the state of all/some objects
(e.g. recreating a database connection)
The code ensures that an open connection or
data stream is closed. Another action that
Close
belongs to this category is the release of a
lock over some resource
The handler performs some kind of assert
operation. This category is separated because
it happens quite a lot. Note that in many
Assert
cases, when the assertion is not successful,
this results in a new exception being thrown
possibly terminating the application
Delegates
A new delegate is added
(only for .NET)
Any kind of action that does not correspond
Others
to the previous ones
To simplify the classification of these error handling actions we propose a small set
of categories that enable the grouping of related actions. These categories are
summarized in the previous table.
Note that an exception handler may contain actions that belong to more than one
category. In fact, this is the common case. For instance, a handler can log an error,
close a connection and exit the application. These actions are represented by three
distinct categories: Log, Close and Return. Thus, in the results, this handler would be
classified in all these three categories.
Since catch and finally handlers have different purposes, we opted for doing
separate counts for each type of handler. Finally, the distribution of handler actions
for each application was calculated as a weighted average accordingly to the number
of actions found in each application. This is so that small applications do not bias the
results towards their specific error handling strategy.
The results obtained for each application group are shown in next four graphs.
The graph of Figure 2 shows the average of results by application group for .NET
catch handlers. In the four application groups 60% to 75% of the total distribution of
handler actions is composed of three categories: Empty, Log and Alternative
Configuration.
Empty handlers are the most common type of handler in Servers and the second
largest in Libraries and Stand-alone applications. This result was completely
unexpected in .NET programs since there are no checked exceptions in the CLR and,
therefore, programmers are not obliged to handle any type of exception. Checked
exceptions can sometimes lead lazy programmers to “silence exceptions” with empty
handlers only to be able to compile their applications. From the analysis of the source
code we concluded that its usage in .NET is not related with compilation but with
avoiding premature program termination on non-fatal exceptions. A typical example
is the presence of several linear protected blocks containing different ways of
performing an operation. This technique assures that if one block fails to achieve its
goal, the execution can continue to the next block without any error being generated.
Logging errors is also one of the most common actions in the handlers of all the
applications. In fact, is the most common action in Server-Apps and Stand-alone
groups? Considering web applications and desktop applications, this typically
corresponds to the generation of an error log, the notification of the user about the
occurrence of a problem and the abortion of the task. This idea is re-enforced by the
value of the Return action category in these two application groups which is the
identical and the highest of all four groups.
The number of Alternative configuration actions reports on the usage of alternative
computation or object’s state reconstruction when the code inside a protected block
fails in achieving its objective. These actions are by far the most individualized and
specialized of all. In some cases they are used to completely replace the code inside
the protected block.
In the Libraries applications group, Assert operations are the second most common
error handling action. Asserts ensure that if an error occurs, the cause of the error is
well known and reported to the user/programmer.
In Servers there is also a high distribution value for the Others category. These
actions are mainly related with thread stopping and freeing resources.
45,0%
40,0%
35,0%
30,0%
25,0%
20,0%
15,0%
10,0%
5,0%
0,0%
Libraries Server-Apps Servers Stand-alone
60,0%
50,0%
40,0%
30,0%
20,0%
10,0%
0,0%
Libraries Server-Apps Servers Stand-alone
120,0%
100,0%
80,0%
60,0%
40,0%
20,0%
0,0%
Libraries Server-Apps Servers Stand-Alone
80,0%
70,0%
60,0%
50,0%
40,0%
30,0%
20,0%
10,0%
0,0%
Libraries Server-Apps Servers Stand-Alone
Another category of actions with some weight in the global distribution is the
Throw action. This is mainly due to the layered and component based development of
software. Layers and components usually have a well defined interface between them.
It is a fairly popular technique to encapsulate all types of exceptions into only one
type when passing an exception object between layers or software components. This
is typically done with a new throw.
Empty, Log, Alternative Configuration, Throw and Return are the actions most
frequently found in the catch handlers of .NET applications. By opposition, Continue,
Rollback, Close, Assert, Delegate and Others actions are rarely used in .NET.
Figure 3 shows the results for catch handlers in Java programs. Only in the Stand-
alone and Server-Apps groups we found some similarity with .NET. Despite this fact,
it is possible to see the same type of clustering found in .NET. The cluster of
categories that concentrate the highest distribution of values is composed by Empty,
Log, Alternative Configuration, Throw and Continue actions.
The distribution values on the Empty category surprised us once again. This value
is lower than the ones found in .NET. This suggests that the checked exception
mechanism has little or no weight on the decision of the programmer to leave an
exception handler empty: another reason must exist to justify the existence of empty
handlers besides silencing exceptions. In .NET this happen quite frequently for
building alternative execution blocks. We risk saying that in Java exception
mechanisms are no longer being used only to handle “exceptional situations” but also
as control/execution flow construct of the language. (Note that even the Java API
sometimes forces this. For instance, the detection of an end-of-file can only be done
by being thrown an exception.)
The Log actions category takes the first place for Server-apps, Server and Stand-
alone application groups and the second place in Libraries group. In this last group,
Log is only surpassed by Throw, another popular action in the Server-Apps and
Server groups. In Java, the Log and Throw actions are highly correlated. We observed
that in the majority of cases, when an object is thrown the reason why it happens is
also logged.
Return is also a common action in all the application groups. Between 7% and 15%
of all handlers terminate the method being executed, returning or not a value.
Figure 4 illustrates the results for finally handlers in .NET. The distribution of the
several actions is different from the one found in catch handlers. Nevertheless, is
visible that the most common handler action category in .NET, for all application
groups, is Close. I.e. finally handlers, in our test suite, are mainly used to close
connections and release resources.
Alternative configuration is the second mostly used handler action in all
application groups with the exception of Libraries. A typical block of code usually
found in finally handlers is composed by some type of conditional test that enables (or
not) the execution of some predetermined configuration. In some cases, these
alternative configuration is done while resetting some state. In those cases, they were
classified as Rollback and not Alternative.
Another common category present in finally handlers of .NET applications is
Others. These actions include file deletion, event firing, stream flushing, and thread
termination, among other less frequent actions. In Server applications it is also
common to reset object’s state or rollback previously done actions.
Finally, on Stand-alone applications there are some empty finally blocks that we
can not justify since they perform no easily understandable function.
In Java applications (Figure 5) the scenario is very similar to the one found in
.NET. Close is the most significant category in all application groups. There are also
some actions classified as Others, which are similar to the ones of .NET. In Java they
have more weight in the distribution, indicating a higher programming heterogeneity
in exception handling.
Rollback and Alternative configuration actions are also used as handler actions in
Java finally handlers.
It is possible to observe that there is some common ground between application
groups in Java and .NET in what concerns exception handling. For the most part,
Empty and Log the most common actions in all catch handlers and Close is the most
used action in finally handlers.
50,0%
40,0%
30,0%
20,0%
10,0%
0,0%
Libraries Server-Apss Servers Stand-alone
System.Exception System.Object
System.IO.IOException System.Security.SecurityException
System.ArgumentException System.FormatException
System.InvalidCastException System.NotSupportedException
System.Net.Sockets.SocketException System.Runtime.Remoting.RemotingException
System.Xml.XmlException
It is possible to observe that programmers prefer to use the most generic exception
classes like System.Exception and System.Object for catching exceptions.
Note that .NET, not C#, allows any type of object to be used as an exception
argument. When the argument clause of a catch statement is left empty, the compiler
assumes that any object can be thrown as an exception. This explains the large
presence of System.Object as argument.
The use of generic classes in catch statements can be related to the two of the most
common actions in handlers: Logging and Return. This means that for the largest set
of possible exceptions that can be thrown, programmers do not have particular
exception handling requirements: they just register the exception or alert the user of
its occurrence. Nevertheless, there are a lot of handlers that use more specific
exception classes. These different handlers do not have any weight by themselves in
the distribution but all the code that actually tries to perform some error recovery
operations is concentrated around these specialized handlers.
I/O related exception handlers are fairly used in Libraries and Servers. Also invalid
arguments types, number and format errors are treated as exceptions by all the
applications as shown by the presence of System.ArgumentException
handlers and System.FormatException handlers.
There are not many differences between Java and .NET in terms of catch
arguments. Figure 7 shows the results for Java. It is possible to conclude that the most
generic exception classes are the preferred ones: Exception, IOException, and
ClassNotFoundException. We tried to found out why
ClassNotFoundException is so commonly used by analyzing the source code.
For the most part, most of the handlers associated to the use of this class are empty,
just log the error or throw a new kind of exception. Others try to load a parent class of
the class not found or another completely different class. In general, these handlers
are associated with “plug-in” mechanisms or modular software components using
dynamic class loading.
Finally, we did an analysis of all the applications source code to find out what was
the distribution of handler actions by catch handler argument class for the most
commonly used classes. The results can be found in Figure 8.
30,0%
25,0%
20,0%
15,0%
10,0%
5,0%
0,0%
Libraries Server-Apps Servers Stand-alone
java.lang.ClassNotFoundException java.lang.Exception
java.io.IOException java.lang.Throwable
java.sql.SQLException java.lang.InterruptedException
java.lang.CloneNotSupportedException java.awt.AWTException
java.lang.IndexOutOfBoundsException org.eclipse.jface.text.BadLocationException
The results are quite different from one type of exception class to another. Even so,
it is still possible to say that the dominant handler actions are the ones belonging to
the categories: Empty, Log, Alternative Configuration, Throw and Return.
50,0%
45,0%
40,0%
35,0%
30,0%
25,0%
20,0%
15,0%
10,0%
5,0%
0,0%
n
n
t
n
ec
..
io
tio
tio
x.
pt
ep
bj
dE
ep
ce
.O
xc
xc
un
Ex
em
.E
.E
Fo
.I O
ng
st
m
ot
Sy
.IO
.la
te
N
ys
va
ss
va
S
ja
la
ja
.C
ng
.la
va
ja
Fig. 8. Handler action distribution for the most used catch handler classes.
On the last section, we reported the exceptions that are used in catch statements.
Nevertheless, a catch statement can catch the specific exception that was listed or
more specific ones (i.e. derived classes). We will now discuss exception handling
code from the point of view of possible handled exceptions. As described in section 4
we used IL code/bytecode analyzers to collect all the exceptions that the applications
could throw because this information is not completely available at source code level.
I.e. the set of exceptions that an application can throw at runtime is not completely
defined by the applications source code throw and throws statements. Therefore, a
profound analysis of the compiled applications was required for gathering this
information.
Table 4. Java and .NET exception classes for bytecode and IL code instructions.
JAVA .NET
java.lang.NullPointerException System.OverflowException
java.lang.IllegalMonitorStateException System.Security.SecurityException
java.lang.ArrayIndexOutOfBoundsException System.ArithmeticException
java.lang.ArrayStoreException System.NullReferenceException
java.lang.NegativeArraySizeException System.DivideByZeroException
java.lang.ClassCastException System.Security.VerificationException
java.lang.ArithmeticException System.StackOverflowException
System.OutOfMemoryException
System.TypeLoadException
System.MissingMethodException
System.InvalidCastException
System.IndexOutOfRangeException
System.ArrayTypeMismatchException
System.MissingFieldException
System.InvalidOperationException
30,0%
25,0%
20,0%
15,0%
10,0%
5,0%
0,0%
Libraries Server-Apps Servers Stand-alone
System.Exception System.Net.Sockets.SocketException
System.Web.HttpException System.ArgumentNullException
System.ArgumentException System.ExecutionEngineException
DotNetOpenMail.MailException OpenSmtp.Mail.SmtpException
System.ApplicationException System.ArgumentOutOfRangeException
50,0%
45,0%
40,0%
35,0%
30,0%
25,0%
20,0%
15,0%
10,0%
5,0%
0,0%
Libraries Server-Apps Servers Stand-alone
java.io.IOException java.security.cert.CertificateEncodingException
java.lang.InterruptedException java.net.SocketException
java.lang.NumberFormatException org.eclipse.core.runtime.CoreException
org.eclipse.jface.text.BadLocationException org.eclipse.jdt.core.JavaModelException
java.lang.Exception javax.jcr.RepositoryException
90,0%
80,0%
70,0%
60,0%
50,0%
.NET
Java
40,0%
30,0%
20,0%
10,0%
0,0%
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
60%
50%
40%
Libraries
Server-Apps
30%
Servers
Stand-alone
20%
10%
0%
2 3 4 5 6 7 8 9 11 12 13 15
In our test set of applications, .NET programmers use much more finally handlers,
relatively to the total number of handlers, than Java programmers.
In the graph of Figure 13 it is possible to see that Java applications have higher
maximum values of catch handlers per protected block, the average number of catch
blocks per try block is almost identical in all the application groups for the two
platforms and has the approximate value of one. The standard deviation values are
also very low meaning that the largest number of protected blocks has only one catch
handler.
5 Libraries
Stand-alone
4
Servers
3 Server-Apps
0
.NET Java .NET Java
Unchecked
Libraries 8,90%
Servers 8,50%
Stand-Alone 36,70%
Server-Apps 6,50%
The results discussed in the previous sections show that programmers, most of the
time, do not use exception handling mechanisms correctly or, at least, they do not use
them for error recovery. These practices lead to a decrease in software quality and
dependability. It is clear that in order to develop high-quality robust software, in a
highly productive way, new advances are needed. Some authors have already started
looking for new approaches. In our line of work we are currently approaching the
problem by trying to create automatic exception handling for the cases where “benign
exception handling actions” can be defined (e.g. compressing a file on a disk full
exception). In general, we are trying to free the programmer from the task of writing
all the exception handling code by hand, forcing the runtime itself to automatically
deal with the problems whenever possible. A complete description of the technique is
out of scope of this paper, but the interested reader can refer to [19] for a discussion
of the approach.
6 Conclusion
This article aimed to show how programmers use the exception handling mechanisms
available in two modern programming languages, like C# and Java. And, although we
have detailed the results individually for both platforms and found some differences,
in the essential results are quite similar. To our knowledge, this is the most extensive
study done on exception handling by programmers in both platforms.
We discovered that the amount of code used in error handling is much less than
what would be expected, even in Java where programmers are forced to declare or
handle checked exceptions.
More important is the acknowledgment that most of the exception classes used as
catch arguments are quite general and do not represent specific treatment of errors, as
one would expect. We have also seen that these handlers most of the times are empty
or are exclusively dedicated to log, re-throw of exceptions or return, exit the method,
or program. On the other hand, the exception objects “caught” by these handlers are
from very specific types and closely tied to application logic. This demonstrates that,
although programmers are very concerned in throwing the exception objects that best
fit a particular exceptional situation, they are not so keen in implementing handling
code with the same degree of specialization.
These results lead us to the conclusion that, in general, exceptions are not being
correctly used as an error handling tool. This also means that if the programming
community at large does not use them correctly, probably it is a symptom of a serious
design flaw in the mechanism: exception constructs, as they are, are not fully
appropriate for handling application errors. Work is needed on error handling
mechanisms for programming languages. Exception handlers are not specific enough
to deal with the detail of the occurring errors; the most preferable behavior is logging
the problem or alerting the user about the error occurrence and abort the on-going
action. Empty handlers, used to “silence” exceptions, will frequently hide serious
problems or encourage bad utilization of programming language error handling
constructs.
Some of the problems detected, like the duplication of code between handlers, and
the mingling of business code with exceptions handling code, among other problems
are still to be tackled and represent an important research target.
We now know, at least for this set of applications, what type of exceptions
programmer prefer to handle and what type of exceptions are commonly caught. In
the future we would like to extend our analysis to running software, actually
accounting what type of exceptions do really occur and how this relates to the code
programmers are forced to write for error handling.