Everyone makes mistakes, not only learners or beginners, but professionals. As a programming course, CodeGym team often collects mistakes of newbies to improve our auto validator. This time we decided to interview experienced programmers about mistakes in Java they made closer to their careers start or noticed them among their young colleagues.
Ignoring JUnit and wrong testing of your own code
Very often, novice programmers “test” their code incorrectly. For example, using System.out.println(), substituting and printing different values to the console. Seriously, from the very first steps, you should learn how to use the excellent JUnit library and write tests for your programs. Moreover, you will definitely need it in your work. Unit testing your own code is a good practice for developers.
Forgetting to free resources
Every time your program opens a file or sets a network connection, you need to free up the resources it uses. It is also true for cases of exceptions when working with resources. Of course, FileInputStream has a finalizer that calls the close() method to collect garbage. However, you can’t be sure about the beginning of the build cycle. Thus, there is a risk that the input stream may consume resources indefinitely.
The problem for beginners is that not freeing resources does not lead to compile-time or run-time errors. So it’s easy to forget about it.
Equals and hashcode problems
The Object class is the parent class for all Java objects. This class has methods equal() and hashCode (). The equals () method, as its name suggests, is used to simply check if two objects are equal. hashCode() method that allows you to get a unique integer number for a given object.
Often newbies don’t feel like these methods need to be overridden for their objects.
The default implementation of equals() method simply checks the two objects by reference to see if they are equivalent.
Wrong work with Wrappers
You need to be careful to remember that Wrapper classes such as Integer or Boolean are reference data types and the type of variable can be null. In this case, it is better to avoid operations in which null doesn’t work well.
Often newbies work with uninitialized variables of type Integer or Boolean somewhere as with int or bool, which can cause NullPointerException errors. For example, if we have any Boolean s, which is Null by default, and they try to call it in some if (s), we will get an error.
Also, autoboxing of variables of primitive types requires an exact match of the type of the original primitive — the type of the “wrapper class”. Attempting to autopack a variable of type byte into Short without first explicitly casting byte-> short will cause a compilation error.
Work with asynchronous code
Experts said that the most common mistakes among developers in general is dealing with asynchronous code (concurrency, threads, etc.).
If in a real project it becomes necessary to work with code asynchronously, you don’t need to use low-level multithreaded programming. It could be beneficial for learning issues or some kind of experimentation. However in a real project this leads to unnecessary complexity and many potential errors. Therefore, when working with multithreading, it is better to use classes from the java.util.concurrent package or other ready-made third-party libraries (Guava, etc.)
OOP: Incorrect construction of the object hierarchy. In particular, a misunderstanding of where to apply an interface, and where an abstract class.
An abstract class lets you create functionality that subclasses can implement or override. In an interface, you just define functionality, but not implement it. Although a class can only extend one abstract class, it can use multiple interfaces.
The choice between interface and abstract class depends on many factors.
- Java does not support multiple inheritance, so each class can inherit only one superclass. However, any class can implement multiple interfaces.
- If you decide to write many methods, then an abstract class is the best solution for you, because you can provide default implementations for some of the methods that are common to all subclasses.
- If you need to add or remove a method from the interface, it could be a problem, because you can’t declare additional methods in an interface without changing all classes that implement this interface.
Let’s look at the example below. Here we have incorrect construction of the object hierarchy. In particular, a misunderstanding of when to apply the interface, and when should be an abstract class.
OOP: mess with order of calling constructors
Newbies often forget about the order that constructors are called when objects are created. The rule is simple: constructors are called in inheritance order. When you think about the logic, it becomes clear that executing constructors in order of inheritance makes some sense.
The superclass knows nothing about its subclasses. Thus, any initialization must be done in the superclass completely independently of any initialization performed by the subclass. Therefore, this should be done first.
OOP: Mess with overriding and overloading
Overriding and Overloading are two very important concepts in Java. They could be really confusing for Java novice programmers.
Simply put, overriding allows you to take a method of the parent class and write its own implementation of this method in each inherited class. The new implementation will “replace” the parent in the child class.
Wrong work with exceptions
Very often novice programmers don’t know how to work with exceptions correctly. To begin with, they simply ignore them, especially those that have moved from other programming languages. However, exceptions are thrown for some reason, so don’t ignore them.
There are also cases of careless handling of exceptions. For example, a newbie writes code, and their IDE starts underlining it in red and explains that certain exceptions may be thrown during its execution.
Problems with choosing the right Collections
Beginners are often confused about choosing the right collection. Sometimes they choose this or that collection by mistake, because they do not deeply understand data structure. The wrong choice can affect the effectiveness of your program. On the other hand, if the collection is selected correctly, your program will look simpler and more logical, and the solution will be more efficient.
To find out which type of collection is right for your task, find out the characteristics and behavior of each one, as well as the differences between them. You need to be clear about the pros and cons of each specific implementation (ArrayList vs LinkedList, treeMap vs HashMap and so on).
I recommend for the first steps:
- Explore not just Сollections framework, but theoretical data structures.
- Create a table with all the collections. Give a brief definition of what data structure is at its core, what are its features.
- Ask yourself some basic questions. Should your collection allow access to items by index? Is null accepted in it? Is it allowed to duplicate elements? Do quick elements addition and quick removal important for your solution? Should it support concurrency?
#6. Ignorance of Java libraries, reinvention of wheels
A huge number of libraries have been written for Java, but beginners often do not notice all these gems. Don’t try to reinvent the wheel, first learn the existing developments on the issue of interest. Many libraries have been perfected by developers over the years, and you can use them for free. For more examples follow the source link.