Java Exception Handling

Java Exception Handling – MalformedURLException

Moving along through the in-depth Java Exception Handling series we’ve been going through, we next arrive at the MalformedURLException. A MalformedURLException is thrown when the built-in URL class encounters an invalid URL; specifically, when the protocol that is provided is missing or invalid.

In today’s article we’ll examine the MalformedURLException in more detail by looking at where it resides in the overall Java Exception Hierarchy. We’ll also take a look at some fully functional code samples that illustrate how a basic HTTP connection might be established using the URL class, and how passing improper URL values to it can result in MalformedURLExceptions, so let’s get started!

The Technical Rundown

All Java errors implement the java.lang.Throwable interface, or are extended from another inherited class therein. The full exception hierarchy of this error is:

Full Code Sample

Below is the full code sample we’ll be using in this article. It can be copied and pasted if you’d like to play with the code yourself and see how everything works.

This code sample also uses the Logging utility class, the source of which can be found here on GitHub.

When Should You Use It?

As the official documentation states, a MalformedURLException is thrown either when “no legal protocol could be found in a specification string,” or when “the string could not be parsed.” In practice, modern Java versions have particularly robust string parsing capabilities, so the vast majority of MalformedURLException occurrences will be due to the former problem: an invalid or unrecognized protocol. The parlance used in Java (and elsewhere) for terms like protocol can be a little confusing, so we’ll briefly refresh ourselves on what this means in the realm of URLs.

To begin with, the broader term for identifiers of network resources is “Unified Resource Identifier”, or URI as it’s more commonly known. A URI is merely a string of characters that identify a resource over a network. Uniformed Resource Locators, or URLs, are a type of URI. A URL is unique in that it typically includes multiple forms of information about accessing the resource, including the protocol, the domain, and the resource to be requested. For example, in the URL https://airbrake.io/blog/ the specified protocol is https, the domain is airbrake.io, and the resource is /blog/.

It’s worth noting that the protocol section is often referred to as the scheme in the parent URI object type, because a URI can contain many different types of schemes to indicate how the resource should be accessed. For example, a scheme of https is common for URLs, but a scheme value of file might be used to access a local file resource. Moreover, many custom URI schemes exist, which allow applications to perform special actions and open resources on behalf of other applications. For example, the popular Steam online gaming platform will recognize and open URIs with a scheme of steam, as shown in the developer documentation.

All that said, since the MalformedURLException in Java is typically thrown via the URL class, it stands to reason that the URL class refers to the scheme portion of the URL as the protocol. To illustrate this in action we begin with a simple HttpMethod enumeration:

This will come in handy in a moment, when we need an easy way to specify the HTTP method we’ll be using for our connection. Speaking of which, we’ve also created a custom HttpResponse class to help simplify the creation and connection process, in order to ultimately retrieve a response from a particular URL that we wish to connect to:

I’ve opted to use a Factory Design Pattern, which we explored in our Creational Design Patterns: Factory Method article, which allows us to execute a sub-method after instantiating a new HttpResponse object. Specifically, we want to execute the initialize() method after the constructor completes, but we also need a way to avoid race conditions, which is where we might get unexpected results if our code is performing multiple connections simultaneously, and where our code could behave differently depending on the order of execution. By avoiding race conditions via the factory method pattern, we ensure that execution always occurs in the order we require.

Thus, client code wishing to create a new HttpResponse instance can only access the create() method overloads, which creates a new HttpResponse instance via the private constructor, then invokes the initialize() method, before finally returning the generated HttpResponse object. The initialize() method is where we perform the actual connection attempt and retrieve the response, so we start by creating a new URL instance from the url property, then open an HTTPS connection to that url. We then set the request method using the string-converted httpMethod property, which is where the HttpMethod enum comes into play. Next, we retrieve the response code and, if it’s valid (200) we process the response by appending each line to an output and assigning the response to the response property.

As a result, client code that invokes the create() method can then immediately call the getResponse() method, which retrieves the formatted (or null) response property value of the HttpResponse instance:

To test this out we’ll create a handful of HttpResponse instances, passing slightly different URL string arguments each time:

The first test produces the following output:

Here we can see that everything appears to be working. We start by establishing a connection to https://airbrake.io, set the request method to GET, set the User-Agent to tha latest Chrome agent string, and get a response code of 200. The full response contains 484 lines, so we truncate that result down to the maximum of 200 characters, as specified in the HttpResponse.MAX_RESPONSE_LENGTH property.

Next, let’s try another test to connect to the slightly incorrect htps://airbrake.io URL:

Immediately we get a MalformedURLException, indicating that the protocol value at the start of our URL is invalid. As previously discussed, URLs are a sub-classification of URIs, so while a URI can have a wide range of standard and custom scheme values, a URL can only have a select handful of accepted protocol values, and htps is not one of them.

Our third test attempts to connect to https://airbrakeio:

Here we see everything works and no MalformedURLException is thrown, but we actually get an UnknownHostException instead. This is because, while https://airbrakeio is a perfectly valid form of URL, it isn’t a recognized host. The same is true when we try to use an invalid character in our host name (,):

The Airbrake-Java library provides real-time error monitoring and automatic exception reporting for all your Java-based projects. Tight integration with Airbrake’s state of the art web dashboard ensures that Airbrake-Java gives you round-the-clock status updates on your application’s health and error rates. Airbrake-Java easily integrates with all the latest Java frameworks and platforms like Spring, Maven, log4j, Struts, Kotlin, Grails, Groovy, and many more. Plus, Airbrake-Java allows you to easily customize exception parameters and gives you full, configurable filter capabilities so you only gather the errors that matter most.

Check out all the amazing features Airbrake-Java has to offer and see for yourself why so many of the world’s best engineering teams are using Airbrake to revolutionize their exception handling practices!