The five most common errors in java are java errors.
[Editor's note] developers often encounter various inexplicable errors during programming. Recently, Sushil Das listed five common errors in Java Development On Geek On Java 」.
The following is a translation:
1. Excessive use of Null
It is a best practice to avoid over-using null values. For example, it is better to let the method return an empty array or collection instead of a null value, because this can prevent the program from throwing NullPointerException. The following code snippet obtains a set from another method:
</> List<String> accountIds = person.getAccountIds(); for (String accountId : accountIds) { processAccount(accountId);}
If a person does not have an account, getAccountIds () returns null, and the program throws an NullPointerException. Therefore, we need to add an empty check to solve this problem. If the returned null value is replaced with an empty list, NullPointerException will not appear. Besides, because we no longer need to check the variable accountId, the code will become more concise.
When you want to avoid null values, different scenarios may adopt different approaches. One method is to use the Optional type, which can be either an empty object or some value encapsulation.
</> Optional<String> optionalString = Optional.ofNullable(nullableString); if(optionalString.isPresent()) { System.out.println(optionalString.get());}
In fact, Java 8 provides a more concise method:
</> Optional<String> optionalString = Optional.ofNullable(nullableString); optionalString.ifPresent(System.out::println);
Java supports the Optional type since Java 8, but it is well known in the world of functional programming. Previously, it was used in earlier versions of Google Guava for Java.
2. Ignore exceptions
We often ignore exceptions. However, for beginners and experienced Java programmers, the best practice is to deal with them. Exception throws are usually purposeful, so you need to record the events that cause exceptions in most cases. Don't underestimate it. If necessary, you can throw it again, display the error information to the user in a dialog box, or record the error information in the log. At least, to let other developers know the cause and effect, you should explain why this exception was not handled.
</> selfie = person.shootASelfie(); try { selfie.show();} catch (NullPointerException e) { // Maybe, invisible man. Who cares, anyway?}
An easy way to emphasize that an exception is not important is to use this information as the variable name of the exception, as shown in the following code:
</> try { selfie.delete(); } catch (NullPointerException unimportant) { }
3. An error occurred while modifying the concurrency.
This exception occurs when the set object is modified and the content in the set is not updated using the method provided by the iterator object. For example, there is an hats list and you want to delete all values containing 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 is thrown because the code traverses this set and modifies it. When multiple processes act on the same list, when one of the processes traverses the list, another process tries to modify the list content. The same exception may also occur.
It is very common to modify the set content concurrently in multiple threads. Therefore, you need to use common methods in concurrent programming, such as synchronization locks and special sets for concurrent modifications. There is a slight difference between Java and multithreading in solving this problem.
Collect objects and delete them in another loop
The direct solution is to put the hats with ear flaps into a list, and then delete it in another loop. However, this requires an additional set to store the hats to be deleted.
</> List<IHat> hatsToRemove = new LinkedList<>(); for (IHat hat : hats) { if (hat.hasEarFlaps()) { hatsToRemove.add(hat); }}for (IHat hat : hatsToRemove) { hats.remove(hat);}
UseIterator.remove
Method
This method is simpler and does not need to create additional sets:
</> Iterator<IHat> hatIterator = hats.iterator(); while (hatIterator.hasNext()) { IHat hat = hatIterator.next(); if (hat.hasEarFlaps()) { hatIterator.remove(); }}
UseListIterator
Method
When the set to be modified implements the List interface, list iterator is a very suitable choice. The iterator that implements the ListIterator interface not only supports the delete operation, but also supportsadd
Andset
Operation. The ListIterator interface implements the Iterator interface.Iterator
Ofremove
The method is similar. The only difference is the hat iterator type and the way we get iterator -- UselistIterator()
Method. The following snippet shows how to useListIterator.remove
AndListIterator.add
Method to replace hat with 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); }}
Use ListIterator to callremove
Andadd
The method can be replaced by calling only oneset
Method:
</> 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 }}
In Java 8stream
Method
In Java 8, developers can convert a collection to stream and filter the stream based on some conditions. This example describes how stream api filters hats and avoidsConcurrentModificationException
. Hats = hats. stream (). filter (hat->! Hat. hasEarFlaps ()))
</> .collect(Collectors.toCollection(ArrayList::new));
Collectors.toCollection
The method creates a new ArrayList, which stores the filtered hats values. If the filter condition filters out a large number of entries, a large ArrayList is generated. Therefore, use it with caution.
In Java 8List.removeIf
Method
You can use another more concise and clear method in Java 8 --removeIf
Method:
</> hats.removeIf(IHat::hasEarFlaps);
At the underlying layer, it usesIterator.remove
To complete this operation.
Use a special set
If you decide to useCopyOnWriteArrayList
InsteadArrayList
Then there will be no problems. BecauseCopyOnWriteArrayList
Provides the modification method (such as set, add, remove). Instead of changing the original set array, it creates a new version. This allows you to traverse the original version set and modify it without throwingConcurrentModificationException
Exception. The disadvantages of this set are also obvious-a new set is generated for each modification.
There are other sets suitable for different scenarios, suchCopyOnWriteSet
AndConcurrentHashMap
.
Another error that may occur when a set is modified concurrently is that a stream is created from a collection and the back-end collection is modified when the stream is traversed. The general rule for stream is to avoid modifying the back-end collection when querying stream. The following example shows how to process stream correctly:
</> List<IHat> filteredHats = hats.stream().peek(hat -> { if (hat.hasEarFlaps()) { hats.remove(hat); }}).collect(Collectors.toCollection(ArrayList::new));
peek
Method to collect all the elements and perform the specified action on each element. Here, the action is to try to delete data from a basic list, which is obviously incorrect. To avoid such operations, you can try some methods described above.
4. Default
Sometimes, for better collaboration, Code provided by a standard library or a third party must comply with common dependency standards. For examplehashCode
Andequals
To ensure a series of collection classes in the Java Collection framework and otherhashCode
Andequals
The method class works normally. Non-compliance does not produce exceptions or corrupt code compilation errors; it is very sinister because it may change application behavior at any time without any danger.
The error code may sneak into the production environment, causing a lot of adverse effects. This includes poor UI experience, incorrect data reports, poor application performance, data loss, or more. Fortunately, these catastrophic errors won't happen frequently. The hashCode and equals conventions have been mentioned before. They may occur in the following scenarios: A set depends on hashing or comparing objects, just like HashMap and HashSet. In short, this Convention has two principles:
- If the two objects are the same, the hash code must be the same.
- If two objects have the same hash code, they may be equal or not equal.
If you attempt to retrieve data from a hashmap, the first criterion of the conventions will be broken. The second criterion means having the samehash code
Objects are not necessarily equal.
The following describes the consequences of undermining the first criterion:
</> 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 is rewritten.equals
AndhashCode
Method. However, it breaks the Convention because hashCode returns a random value for the same object in each call. The following code may not find a name in hashsetEnterprise
Although in fact 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 the convention isfinalize
Method. Here is a reference to the official Java documentation on its function description:
finalize
The General Convention is: when the JavaTM Virtual Machine determines that no thread can access the specified object in any way, this method will be called, and then this object can only be in a certain other (to be terminated) an object or a class is ended as a result of an action.finalize
Methods have multiple functions, including re-enabling this object to be available to other threads; howeverfinalize
The main purpose is to clear the object before it can be undone. For examplefinalize
Method can execute explicit I/O transactions to interrupt the connection before the object is permanently discarded.
You can decide to usefinalize
Method to release resources, but this usage is very bad. Because it is called during garbage collection, and the GC time is not determinedfinalize
The called time cannot be guaranteed.
5. Use the original type instead of parameterized
According to the description in the Java document, the original type is either non-parameterized or non-static member of the class R (and also non-inherited R parent class or parent interface. Before Java generics are introduced, there is no replacement type for the original type. Java has supported generic programming since version 1.5, which is undoubtedly an important feature improvement. However, due to backward compatibility, there is a trap that may damage the entire type system. Focus on the following example:
</> List listOfNumbers = new ArrayList(); listOfNumbers.add(10); listOfNumbers.add("Twenty"); listOfNumbers.forEach(n -> System.out.println((int) n * 2));
A list composed of numbers is defined as the original ArrayList. Because it does not specify a type parameter, you can add any object to it. However, the last line maps the contained elements to the int type and multiplied by 2 to print the data after doubling to the standard output.
This Code does not cause errors during compilation, but once it is run, it throws a runtime error because it attempts to map the character type to an integer. Obviously, if necessary information is hidden, the type system cannot help write security code.
To solve this problem, you need to specify a specific type for the objects stored in the Set:
</> 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 set:
</> List<Integer> listOfNumbers = new ArrayList<>();
The modified code compilation cannot be passed because it attempts to add a string to the set that only expects to store the integer. The compiler will display an error message and point to an attempt to addTwenty
The line of the character. Parameterized generic type is a good idea. In this way, the compiler can check all possible types, thus greatly reducing the chance of running exceptions caused by inconsistent types.
Original article: Top 5 Common Mistake in Java
This article is compiled by OneAPM engineers. OneAPM is an emerging leader in the application performance management field. It helps enterprise users and developers easily achieve slow real-time crawling of program code and SQL statements. For more technical articles, visit the official OneAPM blog.