The 5 most common errors in Java

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

"Editor's note" When programming, developers often encounter a variety of inexplicable errors.

Recently. The Sushil Das lists 5 common errors in Java development in Geek on Java, with "free".

The following are the translations:

1. Excessive use of Null

Avoiding excessive use of null values is a best practice. Like what. A better approach would be to have the method return an empty array or collection instead of a null value. This prevents the program from throwing NullPointerException. The following code snippet obtains a collection from another method:

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

When a person does not have an account, Getaccountids () returns a null value, and the program throws a NullPointerException exception. Therefore, you need to add an empty check to solve the problem. Assume that you replace the returned null value with an empty list. Then NullPointerException will not appear. And. Since we no longer have 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 way to do this is to use the Optional type, which can be an empty object. can also be a package of some values.

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

In fact, JAVA8 provides a more concise approach:

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

Java is supported by the Optional type from the JAVA8 version number. But it has long been known in the world of functional programming.

Before this. It has been used in Google guava for earlier version numbers for Java.

2. Ignoring exceptions

We often ignore exceptions.

However, best practices still deal with those who have just started learning and have experienced Java program apes. Exception throwing is generally purposeful, so in most cases it is necessary to record the event that caused the exception. Don't underestimate the matter. If necessary. You can throw it again. Displays the error message to the user in a dialog box or logs the error message. At least. In order for other developers to be aware of the causes and consequences, you should explain why you did not handle the exception.

person.shootASelfie();try{    selfie.show();}catch{    // 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{  }
3. Concurrency Change exception

Such an exception occurs when the collection object is altered, and at the same time does not use the method provided by the iterator object to update the contents of the collection. Like what. Here is a hats list and want to delete all the values that contain the ear flaps:

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

Assuming this code is executed, Concurrentmodificationexception will be thrown. Because the code changes it at the same time as it iterates through the collection. When multiple processes are acting on the same list. When one process iterates through the list, there is another process that attempts to alter the contents of the list, and the same exception may appear.

It is very common to change the contents of a collection concurrently in multiple threads. Therefore, it is necessary to use the methods commonly used in concurrent programming for processing. For example, synchronous locks, special collections for concurrent changes, and so on. Java has a slight difference in solving problems in single-threaded and multithreaded situations.

Collect objects and delete them in a loop

The immediate solution is to put hats with ear flaps in a list. It is then deleted with a loop. Just 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 approach is simpler, and there is no need to create additional collections at the same time:

</>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 good choice when the list interface is implemented by a collection that needs to be changed. The iterator that implements the Listiterator interface not only supports the delete operation. also supports add and set operates.

The Listiterator interface implements the Iterator interface, so this sample looks Iterator remove very much like the 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 by just calling a set method:

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

Using the methods in Java 8 stream

In Java8, developers are able to convert a collection to stream. and filter the stream based on some conditions. This example describes how the stream API filters hats and avoids them ConcurrentModificationException .


Hats = Hats.stream (). Filter ((Hat,!hat.hasearflaps ()))

.collect(Collectors.toCollection(ArrayList::new));

Collectors.toCollectionMethod will create a new ArrayList. It is responsible for storing the filtered hats values. Assuming that the filter filters out a large number of entries, this will produce a very large ArrayList. Therefore, it is necessary to use it carefully.

Using the methods in Java 8 List.removeIf

There is a more concise and straightforward way to use Java 8- removeIf methods:

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

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

Use a special collection

Assuming that you decide to use it at the beginning CopyOnWriteArrayList instead ArrayList of it, there is no failure. Because CopyOnWriteArrayList of the method of providing the change (such as Set,add. Remove), it does not change the original collection array, but creates a new change version number. This will allow the same time to traverse the original version number collection to make changes, so that no exception is thrown ConcurrentModificationException .

The drawbacks of such collections are also obvious-a new collection is generated for each change.

There are other collections that apply to different scenarios, for example, CopyOnWriteSet and ConcurrentHashMap .

There is also an error that may occur when the collection is concurrently altered by creating a stream from a collection, while traversing the stream, altering the backend's collection at the same time. The general guideline for stream is when querying for a stream. Avoid altering the backend collection. The next 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 executes the intended action on each element. Here, the action is an attempt to delete data from an underlying list, which is obviously wrong. To avoid this, try some of the above explained methods.

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, it is necessary to abide by hashCode equals the common conventions and to ensure that a series of collection classes and other classes of usage and methods in the Java collection framework hashCode equals work correctly. Failure to comply with the Convention does not generate exception or corrupt code compilation errors. It is very insidious because it can change application behavior at any time without a critical hint.

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 many others.

Fortunately, these catastrophic mistakes do not always happen.

The hashcode and equals conventions have been mentioned before. 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:

    • Assume that two objects are equal. Then hash code must be equal.
    • Assuming that 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 having hash code the same object is not necessarily equal.

Here's a look at the consequences of breaking the first rule:

</> Public Static classBoat {PrivateString name; Boat (String name) { This. name = name; } @Override PublicBooleanequals(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 () * the); }}

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 is very likely to find a boat named in HashSet Enterprise , although in fact we have added this type of boat in advance:

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

There is also an example of a contract that is a finalize method.

Here is a reference to the official Java documentation about its functional descriptive narrative:

finalizeThe General convention is that this method is called when the JAVATM virtual machine determines that no matter what thread can no longer access the specified object by any means, the object is then only able to be used as the result of some behavior at the end of some other (ready-to-Terminate) object or class. finalizemethod has several functions, including making this object available to other threads again. finalizethe only primary purpose is to perform a purge operation before discarding the object 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 such as file handlers finalize to free up resources, but this is a very bad way to use them. Because it is called during garbage collection, the GC's time is not deterministic. Therefore finalize the time to be called will not be guaranteed.

5. Use the original type instead of the parameter

According to the description of the Java documentation: the original type is either non-parametric or class R (at the same time not inheriting R parent or parent interface) nonstatic members. Before the Java generics were introduced, there was no alternative type for the original type.

Java started with the 1.5 version to support generic programming, which is undoubtedly an important feature enhancement. However. For backwards compatibility reasons, there is a trap here that could break the entire type system. For the present example:

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

This is a list of numbers that is defined as the original ArrayList.

Because it does not specify a type parameter. So it can be added to whatever object it is. The last line, however, maps the elements it contains to type int and multiplies it by 2, printing the doubled data to standard output.

This code compiles without errors, but once execution throws an execution-time error, as it attempts to map the character type to shaping. Very clearly. Assuming that the necessary information is hidden, the type system will not be able to help write the security code.

In order to solve the problem. You need to specify the detailed type for the objects in the collection:

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

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

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

Code compilation After the change cannot be passed. Because this is an attempt to add a string to a collection that only expects storage shaping. The compiler will display an error message. and point to the line that you tried to add Twenty characters to the list. It's a good idea to count generic types.

In this way, the compiler is able to examine all possible types, resulting in a significant reduction in execution-time exceptions due to inconsistent types.

Original link: Top 5 Common mistake in Java

This article is compiled and organized by OneAPM Project Master. OneAPM is the emerging leader in the field of application performance management. can help enterprise users and developers easily implement: Slow program code and SQL statements in real-time fetching. To read a lot of other technical articles, please visit OneAPM's 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.