10 Annoying Bugs

That who, today wrote a bug again, yes, he said it seems to be me…

As Java development, we will inevitably produce a variety of creative bugs in the process of writing code, some of which are quite frustrating, such as various null pointer exceptions, delete operations in the iteration of ArrayList exceptions, array subscript out of bounds exceptions, etc.

If you happen to see any of the bugs I’ve described in your colleague’s code, you can dump this article on him!! You give him an article and let him pay attention to a wave of Cxuan. You will gain his eyes in the back as if he has won the treasure and worships the great god.

Without further ado, let’s get down to business.

Error 1: Array is converted to ArrayList

Can an Array be converted to an ArrayList? Who is this stupid…

Wait, wait, wait, wait, wait. Let’s see what’s going on.

If we were to convert an array to an ArrayList, we would do something like this

List<String> list = Arrays.asList(arr);
Copy the code

Arrays.aslist () returns an ArrayList, which is a private static class from Arrays that is not the java.util.arrayList class. As shown in the figure below

The internal ArrayList of Arrays only has set, GET, contains and other methods, but there is no method like Add that can change its internal structure, so the size of the internal ArrayList of Arrays is fixed.

If you want to create an ArrayList that can add elements, you can do this:

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
Copy the code

This is possible because the ArrayList constructor accepts a Collection.

Error 2: Checking whether an array contains a value

Check if an array contains a value, as some programmers often do:

Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
Copy the code

This code is correct, but has an additional performance penalty. In normal cases, instead of converting it to set, it would do just fine:

return Arrays.asList(arr).contains(targetValue);
Copy the code

Or use the following method (exhaustive, circular judgment)

for(String s: arr){
	if(s.equals(targetValue))
		return true;
}
return false;
Copy the code

The first paragraph above is more readable than the second.

Error # 3: Iterating through a List

This is a mistake that I’m sure many of you are aware of. Removing elements from loops is a no-no, and for a while I was looking at code to see if the rest of the team made this mistake.

After all, why can’t we do that? Take a look at the code below

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a"."b"."c"."d"));
for (int i = 0; i < list.size(); i++) {
	list.remove(i);
}
System.out.println(list);
Copy the code

Can you imagine the output? Are you itching to take a hit?

The answer is [B, D]

Why only two values? Didn’t I just loop it out?

In fact, inside the list, when you use the external remove, once you remove an element, the internal structure of the list will change. The total capacity of the list is 4, remove an element, it will change to 3, and then compare it with I… So you can only output two elements.

You probably know that using iterators is the correct way to use remove elements, and you probably know that for-each works similarly to iterator, so you write the following code

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a"."b"."c"."d"));
 
for (String s : list) {
	if (s.equals("a"))
		list.remove(s);
}
Copy the code

Then you confidently run xxx.main() and the result… ConcurrentModificationException

Why?

That’s because using the external remove element in an ArrayList causes changes to its internal structure and cursor.

There are also instructions in the Ali development specification not to remove/add elements within the for-each loop.

So if you want to add or remove elements from a List, make sure you use iterators to delete them. That is

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a"."b"."c"."d"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
	String s = iter.next();
 
	if (s.equals("a")) { iter.remove(); }}Copy the code

.next() must be called before.remove(). In the foreach loop, the compiler will call after removing elements operation. The next (), leading to ConcurrentModificationException.

Error # 4: Hashtable and HashMap

This is an algorithmic specification: By algorithm convention, Hashtable is the name of the data structure, but in Java, the name of the data structure is HashMap, and one of the main differences between Hashtable and HashMap is that Hashtable is synchronous, So a lot of times you don’t need a Hashtable, you use a HashMap.

Mistake # 5: Using collections of primitive types

This is a generic constraint:

Primitive types and unbounded wildcard types are easily mixed together in Java. For example, Set is primitive, and Set<? > is an unbounded wildcard type.

For example, the following code takes the primitive type List as an argument:

public static void add(List list, Object o){
	list.add(o);
}
public static void main(String[] args){
	List<String> list = new ArrayList<String>();
	add(list, 10);
	String s = list.get(0);
}

Copy the code

This code will be thrown Java. Lang. ClassCastException, why?

Using sets of primitive types is dangerous because primitive types skip generic checking and are unsafe. Set, Set
is very different from Set, and generics can easily cause type erasure in use.

As you all know, Java generics are pseudo-generics, because all generic information is erased during compilation in Java. The first prerequisite for understanding the concept of generics is to understand type erasure. Java generics are basically implemented at the compiler level. The generated bytecode does not contain the type information in the generics. When the generics are used, the type parameters will be removed when the compiler compiles, and this process is called type erasing.

Defining types such as Listand List

in code becomes a List when compiled, and the JVM sees only the List. The additional type information provided by generics is invisible to the JVM. The Java compiler does everything it can to find errors at compile time, but it still can’t find conversion exceptions at run time. Type erasure is an important difference between the way Java generics are implemented and the way C++ templates are implemented.

Take this example

public class Test {

    public static void main(String[] args) {

        ArrayList<String> list1 = new ArrayList<String>();
        list1.add("abc");

        ArrayList<Integer> list2 = new ArrayList<Integer>();
        list2.add(123); System.out.println(list1.getClass() == list2.getClass()); }}Copy the code

In this example, we define two ArrayList arrays, but one is a generic ArrayList

type that can only store strings. One is the ArrayList

generic type, which can only store integers. Finally, we get information about list1 objects and List2 objects using the getClass() method, and find that the result is true. Note The generic String and Integer types have been erased, leaving only the primitive type.

So, in the top code, adding 10 to Object is perfectly fine, but casting Object “10” to String throws a casting exception.

Error 6: Access level issues

I believe that most developers will simply declare public XXX when designing a class or member variable. This is bad design, and it is easy to be naked, which is dangerous for both classes and member variables.

Mistake 7: ArrayList and LinkedList

Hahaha, ArrayList is one of the most frequently used tool classes I’ve ever seen programmers use.

Developers often use ArrayList when they don’t know the difference between ArrayList and LinkedList (in fact, even if they did, they wouldn’t use LinkedList because that’s not worth mentioning) because ArrayList looks more familiar. .

In practice, however, ArrayList and LinkedList have significant performance differences. In short, LinkedList should be preferred if there are a lot of add/remove operations and not many random access operations. ArrayList is preferred if there is a lot of access, but ArrayList is not suitable for a lot of add/remove operations.

Mistake 8: Mutable and immutable

Immutable objects have many advantages, such as simplicity and security. However, immutable objects need to be allocated a separate object for each different value. Objects are not reusable, and too many of these objects may lead to high garbage collection costs. There needs to be a balance between variable and immutable.

In general, mutable objects are used to avoid creating too many intermediate objects. Let’s say you want to concatenate a bunch of strings. If you use an immutable string, you’ll produce a lot of objects that can be garbage collected immediately. This wastes CPU time and effort, and using mutable objects is the right solution (such as StringBuilder). The following code looks like this:

String result="";
for(String s: arr){
	result = result + s;
}
Copy the code

Therefore, choosing the right mutable object or immutable object requires careful choice.

Mistake 9: Constructors

First, look at a piece of code and analyze why it failed to compile.

This compilation error occurs because the constructor for default Super is not defined. In Java, if a class does not define a constructor, the compiler inserts a default no-argument constructor for that class by default. If a constructor is defined in the Super class, in this case Super(String s), the compiler will not insert the default no-argument constructor. This is the case for the Super class above.

To solve this problem, simply add a parameterless constructor to Super.

public Super(a){
    System.out.println("Super");
}
Copy the code

Mistake 10: Whether to use “” or a constructor

Consider the following code:

String x = "abc";
String y = new String("abc");
Copy the code

Is there any difference between these two pieces of code?

Maybe the following code will give you the answer

String a = "abcd";
String b = "abcd";
System.out.println(a == b);  // True
System.out.println(a.equals(b)); // True
 
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d);  // False
System.out.println(c.equals(d)); // True
Copy the code

This is a typical memory allocation problem.

Afterword.

Today I’ve put together a list of 10 common mistakes in Java development, simple but easy to overlook, with perfect detail, and see if you’ll make them again. If you do, hey hey hey.

“Like” is gay fuck oh! Come quick one key three connect!!