The 5 most common errors in Java

Source: Internet
Author: User
Tags new set stream api concurrentmodificationexception google guava

"Editor's note" When programming, developers often encounter a variety of inexplicable errors. Recently, Sushil das in Geek on Java listed the Java Development Common 5 errors, and June total "free".

The following are the translations:

1. Excessive use of Null

Avoiding excessive use of null values is a best practice. For example, a better approach would be to have the method return an empty array or collection instead of a null value, as this would prevent the program from throwing NullPointerException. The following code snippet obtains a collection from another method:

</>  List<String> accountIds = person.getAccountIds();  for (String accountId : accountIds) {      processAccount(accountId);}

When a person does not have an account, Getaccountids () returns a null value, and the program throws a NullPointerException exception. Therefore, it is necessary to add an empty check to solve this problem. If you replace the returned null value with an empty list, then NullPointerException will not appear. And, because we no longer need to check the variable accountId for short, the code becomes more concise.

When you want to avoid null values, different scenarios may take different approaches. One method is to use the Optional type, which can be either an empty object or a wrapper for some value.

</>  Optional<String> optionalString = Optional.ofNullable(nullableString);  if(optionalString.isPresent()) {      System.out.println(optionalString.get());}

In fact, JAVA8 provides a more concise approach:

</>  Optional<String> optionalString = Optional.ofNullable(nullableString);  optionalString.ifPresent(System.out::println);  

Java is supported by the Optional type from the JAVA8 version, but it has long been well known in the functional programming world. Prior to this, it was already in use in Google guava for earlier versions of Java.

2. Ignoring exceptions

We often ignore exceptions. However, for beginners and experienced Java programmers, best practices still deal with them. Exception throwing is usually purposeful, so in most cases it is necessary to record the event that caused the exception. Don't underestimate it, if necessary, you can re-throw it, display the error message to the user in a dialog box, or record the error message in the log. At the very least, you should explain why you did not handle the exception in order for other developers to be aware of the cause.

</>  selfie = person.shootASelfie();  try {      selfie.show();} catch (NullPointerException e) {    // Maybe, invisible man. Who cares, anyway?}

An easy way to emphasize that an exception is unimportant is to use this information as the variable name for the exception, like this:

</>  try { selfie.delete(); } catch (NullPointerException unimportant) {  }  
3. Concurrency modification Exceptions

This exception occurs when the collection object is modified without using the method provided by the iterator object to update the contents of the collection. For example, here is a hats list, and you want to delete all of the values that contain the ear flaps:

</>  List<IHat> hats = new ArrayList<>();  hats.add(new Ushanka()); // that one has ear flaps  hats.add(new Fedora());  hats.add(new Sombrero());  for (IHat hat : hats) {      if (hat.hasEarFlaps()) {        hats.remove(hat);    }}

If you run this code, Concurrentmodificationexception will be thrown because the code is going through the collection and modifying it. The same exception may occur when multiple processes are acting on the same list, while one process is traversing the list and another process attempts to modify the contents of the list.

It is very common to modify the contents of a collection concurrently in multiple threads, so it is necessary to work with methods commonly used in concurrent programming, such as synchronous locks, special collections for concurrent modifications, and so on. Java has a small difference in how it solves this problem in single-threaded and multithreaded situations.

Collect objects and delete them in another loop

The direct solution is to put hats with ear flaps in a list and then delete it with another loop. However, this requires an additional collection to hold the hats that will be deleted.

</>  List<IHat> hatsToRemove = new LinkedList<>();  for (IHat hat : hats) {      if (hat.hasEarFlaps()) {        hatsToRemove.add(hat);    }}for (IHat hat : hatsToRemove) {      hats.remove(hat);}

How to use Iterator.remove

This method is simpler and does not require the creation of additional collections:

</>  Iterator<IHat> hatIterator = hats.iterator();  while (hatIterator.hasNext()) {      IHat hat = hatIterator.next();    if (hat.hasEarFlaps()) {        hatIterator.remove();    }}

ListIteratorthe method used

The list iterator is a very appropriate choice when the collection that needs to be modified implements the list interface. The iterator that implements the Listiterator interface not only supports delete operations, but also supports add and set operates. The Listiterator interface implements the Iterator interface, so this example looks Iterator remove like a method. The only difference is the type of hat iterator and the way we get iterator--how to use it listIterator() . The following fragment shows how to use ListIterator.remove and ListIterator.add method to replace hat with the ear flaps with sombreros.

</>  IHat sombrero = new Sombrero();  ListIterator<IHat> hatIterator = hats.listIterator();  while (hatIterator.hasNext()) {      IHat hat = hatIterator.next();    if (hat.hasEarFlaps()) {        hatIterator.remove();        hatIterator.add(sombrero);    }}

With Listiterator, calls remove and add methods can be replaced with only one set method called:

</>  IHat sombrero = new Sombrero();  ListIterator<IHat> hatIterator = hats.listIterator();  while (hatIterator.hasNext()) {      IHat hat = hatIterator.next();    if (hat.hasEarFlaps()) {        hatIterator.set(sombrero); // set instead of remove and add    }}

Using the methods in Java 8 stream

In Java8, a developer can convert a collection to stream and filter the stream based on some criteria. This example describes how the stream API filters hats and avoids it ConcurrentModificationException . Hats = Hats.stream (). Filter ((Hat,!hat.hasearflaps ()))

</>   .collect(Collectors.toCollection(ArrayList::new));

Collectors.toCollectionMethod creates a new ArrayList that is responsible for storing the hats values that are filtered out. If the filter filters out a large number of entries, a large ArrayList will be generated here. Therefore, careful use is required.

Using the methods in Java 8 List.removeIf

You can use another, more concise, method in Java 8-- removeIf methods:

</>  hats.removeIf(IHat::hasEarFlaps);  

At the bottom, it is used Iterator.remove to complete this operation.

Use a special collection

If you decide to use it at the very beginning CopyOnWriteArrayList instead ArrayList of it, there is no problem. Because a CopyOnWriteArrayList modified method (for example, Set,add,remove) is provided, it does not change the original collection array, but instead creates a new modified version. This allows changes to be made while traversing the original version collection, so that no exception is thrown ConcurrentModificationException . The drawbacks of this collection are also obvious-a new set is generated for each modification.

There are other collections that apply to different scenarios, such as CopyOnWriteSet and ConcurrentHashMap .

About another error that may occur when the collection is concurrently modified is the creation of a stream from a collection that modifies the collection of the backend while traversing the stream. The general guideline for stream is to avoid modifying the backend's collection when querying the stream. The following example shows how to handle the stream correctly:

</>  List<IHat> filteredHats = hats.stream().peek(hat -> {      if (hat.hasEarFlaps()) {        hats.remove(hat);    }}).collect(Collectors.toCollection(ArrayList::new));

peekMethod collects all the elements and performs a given action on each element. Here, the action is an attempt to delete data from an underlying list, which is obviously wrong. To avoid this, you can try some of the methods explained above.

4. Breach of contract

Sometimes, for better collaboration, code provided by the standard library or by a third party must adhere to common dependency guidelines. For example, you must adhere to hashCode and equals common conventions that ensure that a series of collection classes and other classes of usage and methods in the Java collection framework hashCode equals work correctly. Non-compliance does not result in exception or corrupt code compilation, which is insidious because it can change application behavior at any time without warning.

Error codes can sneak into the production environment, causing a lot of bad effects. This includes poor UI experience, bad data reporting, poor application performance, data loss, or more. Fortunately, these catastrophic mistakes do not happen very often. The hashcode and equals conventions have been mentioned before, and it may appear that a collection relies on hashing or comparing objects, like HashMap and HashSet. In short, there are two criteria for this agreement:

    • If two objects are equal, then hash code must be equal.
    • If two objects have the same hash code, they may or may not be equal.

The first rule of breaking the Convention, when you attempt to retrieve data from a hashmap, will result in an error. The second criterion means that owning hash code the same object is not necessarily equal.

Let's look at the consequences of breaking the first rule:

</>  public static class Boat {      private String name;    Boat(String name) {        this.name = name;    }    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Boat boat = (Boat) o;        return !(name != null ? !name.equals(boat.name) : boat.name != null);    }    @Override    public int hashCode() {        return (int) (Math.random() * 5000);    }}

As you can see, the Boat class overrides the equals and hashCode methods. However, it destroys the convention because Hashcode returns random values for the same object for each invocation. The following code will probably not find a boat named in HashSet Enterprise , despite the fact that we have added this type of boat in advance:

</>  public static void main(String[] args) {      Set<Boat> boats = new HashSet<>();    boats.add(new Boat("Enterprise"));    System.out.printf("We have a boat named ‘Enterprise‘ : %b\n", boats.contains(new Boat("Enterprise")));}

Another example of a contract is a finalize method. Here is a reference to the official Java documentation about its functional description:

finalizeThe general Convention is that when the JAVATM virtual machine determines that any thread can no longer access the specified object in any way, this method is called, and then the object can only be used as the result of a certain behavior at the end of some other (ready-to-Terminate) object or class. finalizemethod has several features, including the ability to make this object available to other threads again, but finalize the primary purpose is to perform a purge before the object is dropped irrevocably. For example, a method that represents an input/output connection object can finalize perform an explicit I/O transaction so that the connection is interrupted before the object is permanently discarded.

You can decide to use methods in such a file processor finalize to free up resources, but this usage is bad. Because it is called during garbage collection, the time of the GC is not deterministic, so finalize the time to be called is not guaranteed.

5. Using the original type instead of the parameterized

According to the Java documentation description: The original type is either nonparametric or non-static member of Class R (and also non-inheriting r parent or parent interface). Before the Java generics were introduced, there was no alternative type for the original type. Java supports generic programming starting with version 1.5, which is undoubtedly an important feature enhancement. However, because of backwards compatibility, there is a trap that could break the entire type system. The following example:

</>  List listOfNumbers = new ArrayList();  listOfNumbers.add(10);  listOfNumbers.add("Twenty");  listOfNumbers.forEach(n -> System.out.println((int) n * 2));  

This is a list of numbers that is defined as the original ArrayList. Because it does not specify a type parameter, you can add any object to it. But the last line maps its contained elements to type int and multiplies it by 2, printing the doubled data to standard output.

This code compiles without errors, but when run, it throws a run-time error because it attempts to map the character type to shaping. Obviously, if the necessary information is hidden, the type system will not be able to help write the security code.

To solve this problem, you need to specify a specific type for the objects that are stored in the collection:

</>  List<Integer> listOfNumbers = new ArrayList<>();listOfNumbers.add(10);  listOfNumbers.add("Twenty");listOfNumbers.forEach(n -> System.out.println((int) n * 2));  

The only difference from the previous code is the line that defines the collection:

</>  List<Integer> listOfNumbers = new ArrayList<>();  

The modified code compilation cannot be passed, as this attempts to add a string to the collection that only expects to store the shaping. The compiler displays an error message and points to the line that you are trying to add Twenty characters to the list. Parameterized generic types is a good idea. In this way, the compiler is able to check all possible types, resulting in a significant decrease in the chance of a run-time exception due to inconsistent types.

Original link: Top 5 Common mistake in Java

This article is compiled and collated by OneAPM engineers. OneAPM is an emerging leader in application performance management, enabling enterprise users and developers to easily implement slow program code and real-time crawling of SQL statements. To read more technical articles, please visit the OneAPM official blog.

The 5 most common errors in Java

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.