As the most popular language on the list, Java is naturally the language most used by developers. Because Java development is so widely used, exceptions are common, so let’s take a look at some of the most common errors in Java development.

One obvious mistake is that Java programmers habitually ignore the large number of libraries that already exist. Before you decide to build a wheel, I suggest you try to search for an existing library. For example, on the logging side, there is LogBack, new Log4J, and on the network side, there is Netty or Akka. Some libraries, such as joda-time in Java8, have gradually become standard. The following is a personal story from my last project. Some of the code used for HTML escaping was done by a developer himself. The code worked fine for years, but once again it encountered a user input, and the code fell into an infinite loop. The user finds that the application is not responding, reenters, and the server hangs because of the loop. If this development had used existing HTML escape tools, such as HtmlEscaper provided by the Google Guava project, this serious problem might not have occurred. And most of the popular open source libraries have teams and communities behind them, so bugs like this can be fixed in a timely manner. 2. The wrong use of break in switch-case is a very embarrassing problem, but it still occurs frequently in actual development. The waterfall feature can be useful in switch statements, but the absence of the necessary break keyword can sometimes be disastrous. For example, in the following code, if we forget to put a break keyword in case 0, the code continues to execute and prints One after Zero: public static void switchCasePrimer() { int caseIndex = 0; switch (caseIndex) { case 0: System.out.println(“Zero”); case 1: System.out.println(“One”); break; case 2: System.out.println(“Two”); break; default: System.out.println(“Default”); }}

The best solution is to use polymorphism and subclass the different processing code. Of course, errors like these can also be detected with tools like FindBugs or PMD. Forgetting to release Resources Once you open a file or establish a network connection, it’s important to remember to close resources. Also, remember that if an error occurs while using a resource like this, you need to do the corresponding shutdown in exception handling. It could be argued that the Java Finalizer will automatically call the close() method of a FileInputStream when it is GC, but we know that we cannot predict when GC will start, so we cannot predict how many resources will not be shut down in time before GC is performed. To avoid this, the try-with-resources syntax introduced in Java7 is worth every development. private static void printFileJava7() throws IOException { try(FileInputStream input = new FileInputStream(“file.txt”)) { int data = input.read(); while(data ! = -1){ System.out.print((char) data); data = input.read(); }}}

The try-with-resources syntax applies to all classes that implement the AutoClosable interface. It ensures that every resource is shut down in a timely manner. Java uses automatic memory management, so most of the time, we don’t care about allocating and freeing memory, but that doesn’t mean Java developers need to ignore memory. Memory problems are also common in Java applications. We know that if an object is not referenced, it will be freed, but that doesn’t mean there won’t be a memory leak. In Java, there are many reasons that cause of memory leaks, but things is the most prone to object references cannot be released, because the GC heap memory in recycling, if an object is still other object references, the object space will not be recycled, for example, if in the class, there is a static field reference to a collection, If we hadn’t manually set the collection to NULL after using it, the collection and its objects would never have been collected because class static fields would not have been GC. For example, another possible cause of a memory leak is when a group of objects refer to each other, often referred to as circular references, so the GC cannot be sure that the objects that refer to each other are still alive. Another scenario is non-heap memory leaks when using JNI. A typical memory leak example: final ScheduledExecutorService ScheduledExecutorService. = Executors newScheduledThreadPool (1); final Deque numbers = new LinkedBlockingDeque<>(); final BigDecimal divisor = new BigDecimal(51);

scheduledExecutorService.scheduleAtFixedRate(() -> { BigDecimal number = numbers.peekLast(); if (number ! = null && number.remainder(divisor).byteValue() == 0) { System.out.println(“Number: ” + number); System.out.println(“Deque size: ” + numbers.size()); } }, 10, 10, TimeUnit.MILLISECONDS);

scheduledExecutorService.scheduleAtFixedRate(() -> {
    numbers.add(new BigDecimal(System.currentTimeMillis()));
}, 10, 10, TimeUnit.MILLISECONDS);
Copy the code

try { scheduledExecutorService.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); }

In the example above, we created two scheduled tasks. The first timed task takes the last number “numbers” from the deque and determines that if the number is divisible by 51, print the size of the number and the deque. The second scheduled task continually adds data to the deque. The two tasks are executed at an interval of 10ms. If this code executes, you’ll see that the size of the deque continues to grow until the entire heap is filled with data in the deque. To prevent this from happening, we can use pollLast instead of peekLast because pollLast removes the last element from the deque as soon as it gets it. Excessive garbage generation means that a program runs a large number of objects with a short declaration period. This results in frequent GC operations to reclaim space from memory, which require heap scans, which can have a significant impact on system performance. Here’s a small example: String oneMillionHello = “”; for (int i = 0; i < 1000000; i++) { oneMillionHello = oneMillionHello + “Hello!” ; } System.out.println(oneMillionHello.substring(0, 6));

In Java, strings are immutable, so each loop creates a new string object. To improve this code, we can use StringBuilder instead: StringBuilder oneMillionHelloSB = new StringBuilder(); for (int i = 0; i < 1000000; i++) { oneMillionHelloSB.append(“Hello!” ); } System.out.println(oneMillionHelloSB.toString().substring(0, 6));

The second version of the code improves performance when executed.

Each of these mistakes is a classic, and solving them is a huge boost to your ability. That’s not all, of course, but if you want to know more about this topic, follow us, and I’ll bring you some other questions that may come up. Hopefully this will help you clear the way for Java.