What is the DRY principle? Why is it useful to follow?

DRY stands for Don’t Repeat Yourself.

It is a very general principle that everyone should keep in mind when writing software. It means that we should avoid repetitions in our code as much as possible. By repetitions we do not necessarily refer to a set of lines or whole lines, it could just mean a string literal, a number, or any smaller fragment of code.

Let’s see a simple example where we use a short formula to calculate a value.

int result = (pointsInFirstRound + pointsInSecondRound) * bonusMultiplier;

It is possible that this formula will be used in multiple places. In order to follow DRY, you should extract it to a method.

private int calculateResult(int pointsInFirstRound, int pointsInSecondRound, int bonusMultiplier) {
    return (pointsInFirstRound + pointsInSecondRound) * bonusMultiplier;

You can call this method any number of times.

Advantages of DRY

Less work

By not repeating code, you have less work to do. If you have a logic that spans 10 lines and you extract it to a method. You will need 1 line instead of 10 lines at every occasion where you use it.

Better maintainability

There is always a chance that your code will need to be changed because a bug is found and you need to fix it or a change request came in. If you have the code in only one place, it’s much easier to modify as you only have to do it once.

Less chance to break the code

If you have to do a change in 10 places, there is a chance that you’ll make a mistake. If the logic is only in 1 place, you have a much higher chance of getting it right.

Better testability

If you extract a piece of code to a well-separated and reusable unit, then unit testing it is easy. You can you test the extracted code and you can mock that logic at every occurrence.

If you have that block of code in several places then you have to take it into account at all of its occurrences. So using DRY makes testing easier.

Better readability

As a result of following DRY, you will have less and better-structured code that is easier to follow.

Disadvantages of DRY

DRY is a great principle to follow but if it is overused it can be a source of issues. If you are trying too hard to make sure that nothing is repeated, it is possible that your code will become too complicated and hard to understand.

You have to weigh the benefits of DRY. Sometimes it’s better to repeat some code if it clearly helps readability a lot.

Exception Handling in Java

Exception handling is the process of handling exceptional situations disrupting the normal flow of an application. This topic is fairly small and even newcomers to Java will come across exceptions pretty soon in their career, so knowing how you can handle exceptions is a must have even for people who consider themselves “junior” java developers.

Java provides a well thought out, object oriented way of handling exceptions. Let’s see the details in the following sections.

Exception handling overview

As I mentioned above, exception handling is the process of handling unexpected situations. These situations can happen for a lot of different reasons. For example, the programmer used nonexisting indexes on an array or tries to call methods on a nonexisting object, the database server could be down, or we could have lost network connection.

In Java, when a situation like this happens, an exception object is created and the JRE will try to find a piece of code that can handle the exception. This process is called throwing an exception. The exception object itself contains a lot of information about what happened. Where did the exception happen, what caused the exception and a complete stack trace that is basically the call hierarchy that led to this exception.

The logic for finding the piece of code that can handle the exception is pretty straightforward. It starts from the method where the exception is thrown and checks if that method can handle the exception. If it cannot handle it, it will go up the call hierarchy until it can find a suitable handler or the end of the call hierarchy is reached. When a handler is found we call it catching the exception. If no handler is found in the call chain, then the application will terminate and print information about the exception.

So now you have a general overview, let’s see the specifics.

Exception hierarchy

The first important part about exceptions is knowing what classes represent them in Java. The hierarchy looks like the following:

The starting point of the hierarchy is Throwable. All exceptions must be the descendant of this class. There are two direct child classes of Throwable: Error and Exception. Also, we have a special type of exception called a RuntimeException.

Exceptions that are of class Exception or any of its subclasses (except RuntimeException) are called checked exceptions because you have to do something (we’ll see later what this is) with them in your code if there is a possibility that they are thrown. On the other hand, exceptions that are instances of RuntimeException or one of its subclasses are called unchecked exceptions because you are not forced to deal with them in your code, but of course, you have the possibility. Errors are usually exceptions that the application cannot recover from.

Checked vs unchecked exceptions

There are two fundamentally different exceptions in Java: checked and unchecked exceptions.

Checked exceptions (Exception and its subclasses)  are exceptions that usually happen because of some outside circumstance. For example, you are trying to open a file but someone has deleted it. Or you are trying to access a database, but the server is down. Most of these situations although not necessarily common, but has a pretty significant chance of happening at one point or another in the life of your application so you have to be prepared for them so your app can act gracefully in these cases.

If your code has a statement that can throw a checked exception, you have to do something with it. You have to either:

  • Catch the exception and handle it in a try-catch block.
  • Declare the exception in the header of your method using the throws keyword.

If you are not doing one of the above, you will be presented with a compilation error.

Unchecked exceptions (RuntimeException and its subclasses) are mostly caused by programming mistakes. For example, you are trying to access a nonexisting index in an array or you are trying to call a method on a null value. Because these can happen at almost any line in your code, handling them at every point would be really inefficient. This is why it is not mandatory to handle them. It would cause a lot of overhead and your code would be unreadable because of excess exception handling logic.

Of course, it won’t hurt if your application can handle these types of exceptions as well. A good practice to this is to handle them somewhere higher in the call hierarchy in a central place. This way, you only have the handler logic at one place but you are doing something with the exception and don’t let the situation escalate to a point where the user sees a stack trace.

The try-catch block

In Java, you can use the so called try-catch block to handle exceptions. This consists of two blocks. The try block contains the code that can throw the exception and the catch block contains code that will handle the exception. Let’s see a simple example.

public class CustomException extends Exception {
RiskyClass riskyClass = new RiskyClass();

try {
} catch (CustomException e) {
    // Handle the exception.

As you can see the try block contains some code that can throw an exception, and there is a catch block that will catch any CustomException thrown in the try block. For catch blocks it is mandatory to specify what exceptions it can catch.

Catching multiple exceptions

You can have multiple catch blocks if needed, like this:

try {
} catch (CustomException e) {
    // Handle the exception.
} catch (IOException e) {
    // Handle the exception.

In case of multiple catch blocks, the JVM will start from the first one and goes until it finds one that can handle the exception. A catch block can handle an exception if the exception specified matches the thrown exception’s class or is a parent of it.

There is an important rule to the ordering of catch blocks. You have to start with the most specific and go towards the least specific. This is because if a less specific one would catch all the exceptions in the beginning, it would be impossible for the code to reach the remaining catch blocks. Here is an example of a correct ordering:

try {
} catch (CustomException e) {
    // Handle the exception.
} catch (IOException e) {
    // Handle the exception.
} catch (Exception e) {
    // Handle any Exception.

The first common superclass for CustomException and IOException is Exception so they can be in any order, but Exception must be specified after them because it is less specific.

Catching multiple exceptions in one block

Since Java 7, you can catch multiple exceptions in a single catch block by separating them with the pipe character. Here’s an example:

try {
} catch (CustomException | IOException e) {
    // Handle the exception.
} catch (Exception e) {
    // Handle any Exception.

The only rule for the exceptions specified in the catch block is that none of them can be the other’s child/parent class as it would mean unnecessary code.

The finally block

You can extend the try-catch block with a finally block. Actually when you have a finally block, you can even omit the catch part.

In the finally block you can specify code that you would like to run regardless of whether an exception was thrown or not.

One of the most common cases is when you are opening a resource (like file stream) in the try block and you would like to be sure that it will be closed even if an exception happens. But that is not the only case. For example, the following code prints how long did the method take to complete in case an exception happens or not.

long startTime = System.currentTimeMillis();
try {
    System.out.println("We are in try.");
} catch (Exception e) {
    System.out.println("We are in catch.");
} finally {
    System.out.println("We are in finally.");
    System.out.println("Total time: " + (System.currentTimeMillis() - startTime) + " ms");

Remember, the finally block always executes except when:

  • System.exit() is called.
  • The JVM crashes.
  • The try block never ends (e.g. endless loop).

Nested exception handlers

You can nest try-catch-finally blocks as deep as you would like. So you can have these blocks inside another try/catch/finally block.

Using try with resources

Before Java 7, it was pretty cumbersome to use some resources that needed to be closed after usage. A resource like this is a BufferedReader that uses a buffered input stream to read characters from for example a file.  Let’s see an example how much code did you need to use it.

BufferedReader bufferedReader = null;
String line;
try {
    bufferedReader = new BufferedReader(new FileReader("file.txt"));

    while ((line = bufferedReader.readLine()) != null) {
} catch (IOException e) {
} finally {
    try {
        if (bufferedReader != null) {
    } catch (IOException ex) {

You can see that a good amount of code was needed just to handle the closing of BufferedReader to free up resources taken by it. You can see that this is boilerplate code as you have to do it the same way every time you are using a resource that needs to be closed.

Java 7 came to the rescue by introducing try with resources. It is basically a special version of the try block where you can specify the resource that you would like to use and the JVM will automatically close it for you.

String line;
try (BufferedReader bufferedReader = new BufferedReader(new FileReader("file.txt"))) {
    while ((line = bufferedReader.readLine()) != null) {
} catch (IOException e) {

As you can see, we could reduce the code to about half of its original size. You can specify as many resources as you want by separating them with semicolons. The only requirement for an object to be listed as a resource is that it has to implement the java.lang.AutoCloseable interface so the compiler can be sure that the classes used to implement a method know how to close the resource.

Declaring unhandled checked exceptions

If one of your methods can throw a checked exception and it is not handled in the method’s code, you have to declare it in the header of the method using the throws keyword.

public void testMethod() throws IOException {
    String line;
    try (BufferedReader bufferedReader = new BufferedReader(new FileReader("file.txt"))) {
        while ((line = bufferedReader.readLine()) != null) {

It is also a good idea to document these exceptions in JavaDoc like this:

 * Test method.
 * @throws IOException Thrown when the IO operation is unsuccessful.
public void testMethod() throws IOException {

Throwing exceptions

Not only code that is coming from external libraries can throw exceptions. Using the throw keyword you can throw an exception any time you want. This is actually pretty often used for signaling to the caller that an exceptional situation has happened in your logic.

public void divide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("You cannot divide by zero.");
    // ...

public void performBusinessLogic(int input) throws CustomException {
    if(input < 0) {
        throw new CustomException("Cannot perform operation with input less than zero");
    // ...

In the first example we are throwing an unchecked exception so it’s not declared in the method’s header. In the second example, a checked exception is thrown so we needed to declare it.

Wrapping exceptions

When you catch an exception it can often be a good idea to throw a new exception in the catch block. In these cases you should wrap the original exception in the new one, so when the new exception will be logged, the original one is logged as well.

try {
    throw new UserNotFoundException("Cannot perform operation with input less than zero");
} catch (UserNotFoundException e) {
    throw new OtherException("Other exception", e);

We called this constructor:

public UserNotFoundException(String message, Throwable cause) {
    super(message, cause);

Custom exceptions

When you are throwing exceptions, those often should be custom exception classes made by you. Here are some examples:

public class UserNotFoundException extends Exception {

    public UserNotFoundException() {

    public UserNotFoundException(String message) {
public class UserAlreadyExistsException extends Exception {

    public UserAlreadyExistsException() {

    public UserAlreadyExistsException(String message) {

You can extend any of the existing exception classes (even yours) and create custom exception hierarchies.

Making and throwing custom exceptions allows you to be as specific as you want about the situation happening and you are able to handle the different exceptional cases in different ways.

Best practices


Properly logging the reason of the exceptions is one of the most important ways to keep your code as easily debuggable as possible. When you are catching an exception it is always a good idea to log a message stating the most concrete info that you know about the exception and you should also print the exception object itself as well. This will print the stack trace as well into the logs. It will come in very handy when someone wants to debug the code.

Of course, printing the exception information to the user is a bad idea. Usually, he won’t understand what is a NullPointerException for example and it can give away information to hackers. For users just print a friendly message that something went wrong and you’ll look into it.

Fail fast

If a method will throw an exception it is best if it throws as early as possible. So for example, if you have some conditions in your method that will result in an exception if not fulfilled, it’s best to check them as soon as you can, so the method won’t run unnecessarily for a longer period of time. This makes debugging easier as well.

Catch only when able to handle

You should only catch an exception when you can act on it properly. Just catching the exception and doing nothing will make debugging your application really hard when an exception happens.

Naming conventions

Your custom exceptions should be named in a way that they end in “Exception” like “CustomException”.

Java Interview Questions About Strings

What are Strings in Java?

Strings represent a sequence of characters. In Java, String is not a primitive data type like int or long, they are objects and the characters are stored internally as a char array.

The String class is used to represent strings and provides some methods that can be used to manipulate them and perform various operations.

How can you create Strings in Java?

The most common way to create a String is to use a literal like so:

String myString = "Hello World";

You will use this 99% of the time, but there can be cases when you would like to use one of the constructors of the String class (like when creating a String from a character array).

What is important to remember here is not to use this constructor:

new String("Hello World")

This will first create a new String from the literal that you specified (“Hello World”), it will then pass this to the constructor and that will create another String object with the same value. You have 2 objects instead of one, this is really inefficient.

How to check if two Strings are equal?

There are two ways to check for String equality.

The first way is to use the double equal sign (==). In most cases however this will not provide the expected result, because it will compare the references of the two Strings and those might not be the same. Two different String objects could exist with the same value, but their reference will not be the same.

The recommended way is to use the equals() method. It will work as expected because it will only compare the value of the two String objects.

Why there are classes like StringBuilder or StringBuffer?

Performing a lot of operations (like concatenation) on a String until you reach it’s final form can result in creating a lot of String objects, because each of these operations have the chance of creating a new object because of String’s immutability.

StringBuilder and StringBuffer helps in this situation by keeping track of the String you are building as a character array. It will only produce a String object when you are done with the building of the String and ask StringBuilder/StringBuffer to return the result.

Let’s see an example. Without StringBuilder:

String stringByConcatenation = "Hello";

stringByConcatenation += " ";
stringByConcatenation += "World";
stringByConcatenation += "!";

After executing these lines we will have the following String objects:

  • 4 String literals we see in the code.
  • 3 intermediate results during the concatenation.

With StringBuilder:

StringBuilder builder = new StringBuilder("Hello");
builder.append(" ");

String stringFromBuilder = builder.toString();

After executing these lines we will have the following String objects:

  • 4 String literals we see in the code.
  • 1 extra String when we call toString().

As you can see in this example we have 5 instead of 7 strings. In more complex examples, the win would be even higher. For 1000 strings, it would be 1999 (without StringBuilder) vs 1001 (with StringBuilder).

What is the difference between StringBuilder and StringBuffer?

StringBuffer is synchronized, StringBuilder is not.

What does it mean that a String is immutable?

It means that once a String object is created, it’s value cannot be changed. More on that here: What is the difference between final and immutable in Java?

Are Strings thread safe?

Strings are thread safe, because they are immutable so their state cannot change after they are created.

What is String interning?

See our separate article on this topic: What is String interning in Java?

Bonus: Why could String’s substring() method cause a memory leak in JDK6?

In JDK6 the String class contained three fields: value, offset, count.

  • value – The characters of the String as a char array.
  • offset – The first index of the array.
  • count – The number of characters in the String.

When the substring() method was called, it just created a new String object that contained the same value, but used a different offset and count. As a result the new object referenced the old object and made it impossible for it to be garbage collected. If you had a lot of huge Strings, this wasted memory could add up to large amounts.

Here is the String constructor that causes the mentioned problem in JDK6.

String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;

In JDK7, this issue has been resolved. The String class no longer has the offset and count fields. When the substring() method is used, a new String is created by copying the required characters to a new object.

What is the Difference Between Final and Immutable in Java?


If you declare a field or variable final, it means, that you cannot change the object reference stored in it. It will always point to the same object. While you cannot substitute the stored reference with another one, you can modify the referenced object (for example update its fields).

For classes, final means that you cannot create a subclass of it.

Making something final is just a matter of adding a keyword, reaching immutability is a bit more complex.


If an object is immutable, it’s state/value cannot change over time. A good example for this is the String or the BigDecimal class.

BigDecimal for example, has a number of “manipulation” methods like add(), but these methods will not modify the original object, but they will return a new one.

public BigInteger add(BigInteger val) {
        // ...
        return new BigInteger(resultMag, cmp == signum ? 1 : -1);

Making an object immutable is the responsibility of the programmer. It cannot be achieved just by putting there a keyword like in case of final.

Final and immutable

Of course, it is possible for an object to be final and immutable at the same time. A good example for this is the String class.

Java Interview Questions about the static keyword

What is the static keyword for?

The static keyword means that a field or a method belongs to a class and not to an instance of the class. So it can be accessed without the need for an instance of it’s containing class.

Even if there are multiple instances of a class, the static fields will have only one instance shared between all of the class instances.

Can a class be static?

No, you can’t use the static keyword for a top-level class definition, it only has a meaning for members inside a class.

Think about it, what would it mean for a class to be static? In java, a static element means that you can access/invoke it without an instance of the enclosing class; what that could possibly mean if you apply the keyword to the class itself?

However, you can use the static keyword for inner classes. This way you can create an inner class that can have an instance without requiring an instance of the parent class.

What is a static inner class?

It is a class defined inside another class, using the static modifier. It is not tied to an instance of the outer class, you can reference it on it’s own even from outside of the class by prefixing it with the outer class’s name.

Example of such a class (Address):

public class Person {

    static class Address {
        private String city;
        private String street;

        public Address(String city, String street) {
            this.city = city;
            this.street = street;

And it’s usage from outside of the class:

new Person.Address("Budapest", "Futo street");

Of course, you can also create an instance of it inside the class. In that case, you do not need to use the Person prefix.

Can you override a static method?

No, you can not override a private method in Java, if you create a similar method with same return type and same method arguments in descendant class then it will hide the superclass method, this is known as method hiding.

Is there a way for a static method of a class to access an instance variable of an instance of the same class?

The first guess could be for many people that it is not possible. This is true in most cases, because inside a static method you are not inside an instance of the containing class.

However, your method can take parameters. If you can pass the instance that you need to access as a parameter, you will be able to access it’s fields and methods that are visible.

When are static fields initialized?

Static fields are initialized at the time of class loading in Java, opposite to instance variable which is initialized when you create instance of a particular class.

What is the initialization order of static fields?

Static fields are initialized based on the textual order they appear in the code.

What risks can you think of regarding static fields and parallel running?

In a concurrent environment you need to take extra care to ensure that static fields won’t get in an unwanted state because of multiple threads are modifying it at the same time.

Of course, this issue can be present with non static fields as well, but static fields can be more easily accessed from various parts of a program.

A great way to prevent this issue is to make them final, so their value cannot change.

What are the disadvantages of a static method in Java?

You cannot override a static method in Java. This makes testing harder as you can’t replace it with a mock.

However there are ways to overcome this limitation if you really want to mock some static methods:

  • Use a tool like PowerMock.
  • Create a wrapper class around the static class and inject the wrapper. You can then mock it as well. But in this case it is wise to think it through if you really need to have your methods as static.

What is a static initializer block?

The static initializer block is a block of code that gets executed when the class is loaded by the JVM. This happens the first time it is referenced in the code.


public class MyClass {

    private static String computedComplexValue;

    static {
        // Imagine a complicated computation here.
        String firstName = "John";
        String lastName = "Doe";
        computedComplexValue = firstName + lastName;

Are static initializer blocks thread safe?

Yes they are. The is no issue when multiple threads are trying to load the same class and run it’s static init block. It will only be loaded and executed once.

Multiple executions are only possible if you have multiple classloaders that load the class.

What is the execution order for static initializer blocks?

If you define multiple static blocks in a class, they will execute in the order they are define.

When you have multiple static blocks in you inheritance hierarchy, they will execute in order from super classes to child classes.