Saturday, July 8, 2017

Most Common Mistakes Of Java Developers


NO. 1: Neglecting Existing Libraries

It's unquestionably a mix up for Java Developers to slight the endless measure of libraries written in Java. Just before reexamining the wheel, attempt to chase for offered libraries – a few of them have been cleaned during the time of their reality and are thoroughly allowed to utilize. These could be logging accumulations, as logback and Log4j, or system applicable accumulations, as Netty or Akka. A couple of the libraries, for example, Joda-Time, have really come to be an accepted necessity.

NO. 2: Missing the ‘break’ Keyword in a Switch-Case Block



 Fall through behavior in switch statements is often useful; however, missing a “break” keyword when such behavior is not desired can lead to disastrous results. If you have forgotten to put a “break” in “case 0” in the code example below, the program will write “Zero” followed by “One”, since the control flow inside here will go through the entire “switch” statement until it reaches a “break”. For example:

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");
                }
}

In most cases, the cleaner solution would be to use polymorphism and move code with specific behaviors into separate classes. Java mistakes such as this one can be detected using static code analyzers, e.g. FindBugsand PMD.

NO. 3: Forgetting to Free Resources



This mistake may lead to resources leaked or memory occupied by no longer used objects.

public static void copyFile(File sourceFile, File destFile) {

    FileChannel sourceChannel = null;
    FileChannel destChannel = null;

    try {

        sourceChannel = new FileInputStream(sourceFile).getChannel();
        destChannel = new FileOutputStream(destFile).getChannel();
        sourceChannel.transferTo(0, sourceChannel.size(), destChannel);

    } catch (IOException ex) {
        ex.printStackTrace();
    }
}
A solution to this is using the try-with-resources structure available since Java 7, which automatically closes the resources. example, the above code can be re-written like the following code:
public static void copyFile(File sourceFile, File destFile) {

    try (

        FileChannel sourceChannel = new FileInputStream(sourceFile).getChannel();

        FileChannel destChannel = new FileOutputStream(destFile).getChannel();
    ) {

        sourceChannel.transferTo(0, sourceChannel.size(), destChannel);

    } catch (IOException ex) {
        ex.printStackTrace();
    }

}


NO. 4: Memory Leaks

Memory leaks in Java can happen in various ways, but the most common reason is everlasting object references, because the garbage collector can’t remove objects from the heap while there are still references to them. One can create such a reference by defining class with a static field containing some collection of objects, and forgetting to set that static field to null after the collection is no longer needed. Static fields are considered GC roots and are never collected.
Another potential explanation for such memory spills is a gathering of items referencing each other, causing round conditions so the junk jockey can't choose whether these articles with cross-reliance references are required or not. Another issue is spills in non-load memory when JNI is utilized.

NO. 5: Excessive Garbage Allocation

Excessive garbage allocation may happen when the program makes a ton of fleeting items. The junk jockey works consistently, expelling unneeded articles from memory, which impacts applications' execution adversely.

An 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, on each iteration a new string is created. To address this we should use a mutable StringBuilder:
StringBuilder oneMillionHelloSB = new StringBuilder();
    for (int i = 0; i < 1000000; i++) {
        oneMillionHelloSB.append("Hello!");
    }
System.out.println(oneMillionHelloSB.toString().substring(0, 6));

While the principal rendition requires a considerable amount of time to execute, the form that utilizations StringBuilder produces an outcome in an essentially less measure of time.

NO. 6: Using Null References without Need

Maintaining a strategic distance from inordinate utilization of invalid is a decent practice. For instance, it's desirable over return discharge exhibits or accumulations from techniques rather than nulls, since it can help avert NullPointerException.

Consider the accompanying technique that navigates an accumulation acquired from another strategy, as demonstrated as follows:

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

If getAccountIds() returns null when a person has no account, then NullPointerException will be raised.To settle this, an invalid check will be required. Be that as it may, if rather than an invalid it restores a void rundown, at that point NullPointerException is not any more an issue. Besides, the code is cleaner since we don't have to invalid check the variable accountIds.

To manage different situations when one needs to stay away from nulls, distinctive techniques might be utilized. One of these techniques is to utilize Optional sort that can either be a void protest or a wrap of some esteem:

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

In fact, Java 8 provides a more concise solution:
Optional<String> optionalString = Optional.ofNullable(nullableString);
optionalString.ifPresent(System.out::println);


NO. 7: Ignoring Exceptions

 In This case the exceptions occurred, the code can fail silently which adds difficulty in finding the problem.
look at the following program:
public class Sum {
    public static void main(String[] args) {
        int a = 0;
        int b = 0;

        try {
            a = Integer.parseInt(args[0]);
            b = Integer.parseInt(args[1]);

        } catch (NumberFormatException ex) {
        }

        int sum = a + b;

        System.out.println("Sum = " + sum);
    }
}

program calculates the sum of two numbers passed via command-line arguments. Note that the catch block is left empty. If we try to run this program by the following command line:

java Sum 123 456y

will fail silently:
Sum = 123

It’s because the second argument 456y causes a NumberFormatException to be thrown, but there’s no handling code in the catch block so the program continues with incorrect result.
So to avoid such potential problem, always handle exceptions at least by printing the stack trace to inform the error when it happens:

try {
    a = Integer.parseInt(args[0]);
    b = Integer.parseInt(args[1]);

} catch (NumberFormatException ex) {
    ex.printStackTrace();
}


It save your hours of debugging later if the problem occurs.

NO. 8: Modifying a collection while iterating it

This exemption happens when a gathering is changed while repeating over it utilizing techniques other than those gave by the iterator protest. For instance, we have a rundown of caps and we need to evacuate every one of those that have ear folds:

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 raised since the code modifies the collection while iterating it. The same exception may occur if one of the multiple threads working with the same list is trying to modify the collection while others iterate over it. Simultaneous change of accumulations in numerous strings is a characteristic thing, yet ought to be treated with regular apparatuses from the simultaneous programming tool kit, for example, synchronization locks, exceptional accumulations embraced for simultaneous adjustment, and so forth. There are inconspicuous contrasts to how this Java issue can be settled in single strung cases and multithreaded cases. The following is a concise discourse of some ways this can be dealt with in a solitary strung situation:

Gather questions and evacuate them in another circle
Gathering caps with ear folds in a rundown to expel them later from inside another circle is a conspicuous arrangement, however requires an extra accumulation for putting away the caps to be expelled:

List<IHat> hatsToRemove = new LinkedList<>();
for (IHat hat : hats) {
    if (hat.hasEarFlaps()) {
        hatsToRemove.add(hat);
    }
}
for (IHat hat : hatsToRemove) {
    hats.remove(hat);
}
Use Iterator.remove method
This approach is more concise, and it doesn’t need an additional collection to be created:
Iterator<IHat> hatIterator = hats.iterator();
while (hatIterator.hasNext()) {
    IHat hat = hatIterator.next();
    if (hat.hasEarFlaps()) {
        hatIterator.remove();
    }
}

Utilizing List Iterator’s methods
Utilizing the listiterator is suitable when the adjusted gathering actualizes List interface. Iterators that execute List Iterator interface bolster evacuation operations, as well as include and set operations. ListIterator actualizes the Iterator interface so the illustration would look practically the same as the Iterator evacuate technique. The main distinction is the kind of cap iterator, and the way we acquirethat iterator with the “listIterator()” method. The snippet below shows how to replace each hat with ear flaps with sombreros using “ListIterator.remove” and “ListIterator.add” methods:

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, the remove and add method calls can be replaced with a single call to set:
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
    }
}

Utilize stream strategies presented in Java 8 With Java 8, software engineers can change a gathering into a stream and channel that stream as indicated by a few criteria. Here is a case of how stream programming interface could enable us to channel caps and evade

“ConcurrentModificationException”.
hats = hats.stream().filter((hat -> !hat.hasEarFlaps()))
        .collect(Collectors.toCollection(ArrayList::new));

The “Collectors.toCollection” technique will make another ArrayList with separated caps. This can be an issue if the separating condition were to be fulfilled by an expansive number of things, bringing about a huge ArrayList; subsequently, it ought to be use with mind. Utilize List.removeIf strategy displayed in Java 8 Another arrangement accessible in Java 8, and plainly the most succinct, is the utilization of the “removeIf” method:
hats.removeIf(IHat::hasEarFlaps);

That’s it. Under the hood, it uses “Iterator.remove” to accomplish the behavior.

Utilize specialized collections
On the off chance that at the earliest reference point we chose to utilize "CopyOnWriteArrayList" rather than "ArrayList", at that point there would have been no issue by any means, since "CopyOnWriteArrayList" gives adjustment techniques, (for example, set, include, and evacuate) that don't change the support exhibit of the gathering, but instead make another altered form of it. This permits emphasis over the first form of the gathering and alterations on it in the meantime, without the danger of "ConcurrentModificationException". The downside of that gathering is self-evident - era of another accumulation with every adjustment.

There are other collections tuned for different cases, e.g. “CopyOnWriteSet” and “ConcurrentHashMap”.
Another possible mistake with concurrent collection modifications is to create a stream from a collection, and during the stream iteration, modify the backing collection. The general rule for streams is to avoid modification of the underlying collection during stream querying. The following example will show an incorrect way of handling a stream:
List<IHat> filteredHats = hats.stream().peek(hat -> {
    if (hat.hasEarFlaps()) {
        hats.remove(hat);
    }
}).collect(Collectors.toCollection(ArrayList::new));

The strategy look accumulates every one of the components and plays out the gave activity on every one of them. Here, the activity is endeavoring to expel components from the basic rundown, which is incorrect. To maintain a strategic distance from this, attempt a portion of the strategies portrayed previously.

NO. 9: Breaking Contracts

Sometimes, code that is provided by the standard library or by a third-party vendor relies on rules that should be obeyed in order to make things work. For example, it could be hashCode and equals contract that when followed, makes working guaranteed for a set of collections from the Java collection framework, and for other classes that use hashCode and equals methods. Disobeying contracts isn’t the kind of error that always leads to exceptions or breaks code compilation; it’s more tricky, because sometimes it changes application behavior without any sign of danger. Erroneous code could slip into production release and cause a whole bunch of undesired effects. This can include bad UI behavior, wrong data reports, poor application performance, data loss, and more. Fortunately, these disastrous bugs don’t happen very often. I already mentioned the hashCode and equals contract. It is used in collections that rely on hashing and comparing objects, like HashMap and HashSet. Simply put, the contract contains two rules:
If two objects are equal, then their hash codes should be equal.
If two objects have the same hash code, then they may or may not be equal.
Breaking the contract’s first rule leads to problems while attempting to retrieve objects from a hashmap. The second rule signifies that objects with the same hash code aren’t necessarily equal. Let us examine the effects 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, class Boat has overridden equals and hashCode methods. However, it has broken the contract, because hashCode returns random values for the same object every time it’s called. The following code will most likely not find a boat named “Enterprise” in the hashset, despite the fact that we added that kind of boat earlier:
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 contract involves the finalize method. Here is a quote from the official java documentation describing its function:
”The general contract of finalize is that it is invoked if and when the JavaTM virtual machine has determined that there is no longer any means by which this object can be accessed by any thread (that has not yet died), except as a result of an action taken by the finalization of some other object or class which is ready to be finalized. The finalize method may take any action, including making this object available again to other threads; the usual purpose of finalize, however, is to perform cleanup actions before the object is irrevocably discarded. For example, the finalize method for an object that represents an input/output connection might perform explicit I/O transactions to break the connection before the object is permanently discarded.“
One could decide to use the finalize method for freeing resources like file handlers, but that would be a bad idea. This is because there’s no time guarantees on when finalize will be invoked, since it’s invoked during the garbage collection, and GC’s time is indeterminable.

NO. 10: RAW TYPE USAGE

Raw types, according to Java specifications, are types that are either not parametrized, or non-static members of class R that are not inherited from the superclass or superinterface of R. There were no alternatives to raw types until universal types were presented in Java. It sustains generic programming considering that version 1.5, and generics were unquestionably a significant improvement. Nonetheless, due to backwards compatibility factors, a mistake has been left that can potentially break the type system.

6 comments:

  1. Great article, Thanks for your nice knowledge, the content is quiet attention-grabbing. i will be expecting your next post.

    ReplyDelete
  2. I am extremely impressed along with your writing abilities, Thanks for this great share.

    ReplyDelete
  3. "Mistakes Of Java Developers" nice article Thanks

    ReplyDelete
  4. It's great that you are getting ideas from this piece of writing as well as from our dialogue made at this time
    .

    ReplyDelete