Friday, April 3, 2015

newFixedThreadPool, Callable and Future example in Java

In this article, we will learn how to implement tasks that return a result and run them on an executor using Callable and Future interfaces with the help Executor framework. This post is continuation of previous post where we learned about cached Thread pool

One of the advantages of the Executor framework is that you can run concurrent tasks that return a result. The Java Concurrency API achieves this with the following two interfaces:

  • Callable: This interface has the call() method. In this method, you have to implement the logic of a task. The Callable interface is a parameterized interface, meaning you have to indicate the type of data the call() method will return.
  • Future: This interface has some methods to obtain the result generated by a Callable object and to manage its state



Create a class named FactCalculator that implements the Callable interface parameterized with the Integer type



Implement the Main class


Output

  Number of completed task : 0
  Task 0 status : false
  Task 1 status : false
  Task 2 status : false
  Task 3 status : false
  Task 4 status : false
  Task 5 status : false
  Task 6 status : false
  Task 7 status : false
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 1
  Task 0 status : true
  Task 1 status : false
  Task 2 status : false
  Task 3 status : false
  Task 4 status : false
  Task 5 status : false
  Task 6 status : false
  Task 7 status : false
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 2
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : false
  Task 4 status : false
  Task 5 status : false
  Task 6 status : false
  Task 7 status : false
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 3
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : false
  Task 4 status : false
  Task 5 status : false
  Task 6 status : false
  Task 7 status : false
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 3
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : true
  Task 4 status : false
  Task 5 status : false
  Task 6 status : false
  Task 7 status : false
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 4
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : true
  Task 4 status : false
  Task 5 status : false
  Task 6 status : false
  Task 7 status : false
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 4
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : true
  Task 4 status : true
  Task 5 status : false
  Task 6 status : false
  Task 7 status : false
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 6
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : true
  Task 4 status : true
  Task 5 status : false
  Task 6 status : true
  Task 7 status : false
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 6
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : true
  Task 4 status : true
  Task 5 status : true
  Task 6 status : true
  Task 7 status : true
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 8
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : true
  Task 4 status : true
  Task 5 status : true
  Task 6 status : true
  Task 7 status : true
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 8
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : true
  Task 4 status : true
  Task 5 status : true
  Task 6 status : true
  Task 7 status : true
  Task 8 status : false
  Task 9 status : false
  Number of completed task : 8
  Task 0 status : true
  Task 1 status : true
  Task 2 status : true
  Task 3 status : true
  Task 4 status : true
  Task 5 status : true
  Task 6 status : true
  Task 7 status : true
  Task 8 status : false
  Task 9 status : false
  Main result : 
  Result of Task: 0 2
  Result of Task: 1 120
  Result of Task: 2 6
  Result of Task: 3 720
  Result of Task: 4 362880
  Result of Task: 5 362880
  Result of Task: 6 2
  Result of Task: 7 24
  Result of Task: 8 40320
  Result of Task: 9 40320


How it works...
In this example, we have learned how to use the Callable interface to launch concurrent tasks that return a result. You have implemented the FactorialCalculator class that implements the Callable interface with Integer as the type of the result. Hence, it returns before type of the call() method.
The other important point of this example is in the Main class. You send a Callable object to be executed in an executor using the submit() method. This method receives a Callable object as a parameter and returns a Future object that you can use with two main objectives

  • You can control the status of the task: you can cancel the task and check if it has finished. For this purpose, you have used the isDone() method to check if the tasks had finished.
  • You can get the result returned by the call() method. For this purpose, you have used the get() method. This method waits until the Callable object has finished the execution of the call() method and has returned its result. If the thread is interrupted while the get() method is waiting for the result, it throws an InterruptedException exception. If the call() method throws an exception, this method throws an ExecutionException exception.

There's more...
When you call the get() method of a Future object and the task controlled by this object hasn't finished yet, the method blocks until the task finishes. The Future interface provides another version of the get() method.


get(long timeout, TimeUnit unit): This version of the get method, if the result of the task isn't available, waits for it for the specified time. If the specified period of time passes and the result isn't yet available, the method returns a null value. The TimeUnit class is an enumeration with the following constants: DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, and SECONDS.



That's all. Thanks for reading this and if you found this article useful, I would like to see your appreciation in the form of comments.



If you know anyone who has started learning Java, why not help them out! Just share this post with them. Thanks for studying today!...

Thursday, April 2, 2015

newCachedThreadPool example in Java

The first step to work with the Executor framework is to create an object of the ThreadPoolExecutor class. You can use the four constructors provided by that class or use a factory class named Executors that creates ThreadPoolExecutor. Once you have an executor, you can send Runnable or Callable objects to be executed. 
In this  article, you will learn how these two operations implement an example that will simulate a server processing requests from various clients. Before that you can have an overview of Executor frameworks in my previous article.



First, you have to implement the tasks that will be executed by the server. Create a class named Task that implements the Runnable interface


Now, implement the CachedPoolServer class that will execute every task it receives using an executor


Finally, implement the main class of the example by creating a class named Main and implement the main() method



How it works...
The main part of this example is the CachedPoolServer class. This class creates and uses ThreadPoolExecutor to execute tasks

The first important point is the creation of ThreadPoolExecutor in the constructor of the Server class. The ThreadPoolExecutor class has four different constructors but, due to their complexity, the Java concurrency API provides the Executors class to construct executors and other related objects. Although we can create  threadPoolExecutor directly using one of its constructors, it's recommended to use the Executors class.

In this case, you have created a cached thread pool using the newCachedThreadPool() method. This method returns an ExecutorService object, so it's been cast to ThreadPoolExecutor to have access to all its methods. The cached thread pool you have created creates new threads if needed to execute the new tasks, and reuses the existing ones if they have finished the execution of the task they were running, which are now available. The reutilization of threads has the advantage that it reduces the time taken for thread creation. The cached thread pool has, however, a disadvantage of constant lying threads for new tasks, so if you send too many tasks to this executor, you can overload the system

Tip
Use the executor created by the newCachedThreadPool() method only when you have a reasonable number of threads or when they have a short duration.

Once you have created the executor, you can send tasks of the Runnable or Callable type for execution using the execute() method. In this case, you send objects of  the Task class that implements the Runnable interface.

We also have printed some log messages with information about the executor. Specifically, you have used the following methods:

  • getPoolSize(): This method returns the actual number of threads in the pool of the executor
  • getActiveCount(): This method returns the number of threads that are executing tasks in the executor.
  • getCompletedTaskCount(): This method returns the number of tasks completed by the executor


One critical aspect of the ThreadPoolExecutor class, and of the executors in general, is that you have to end it explicitly. If you don't do this, the executor will continue its execution and the program won't end. If the executor doesn't have tasks to execute, it continues waiting for new tasks and it doesn't end its execution. A Java application won't end until all its non-daemon threads finish their execution, so, if you don't terminate the executor, your application will never end.


To indicate to the executor that you want to finish it, you can use the shutdown() method of the ThreadPoolExecutor class. When the executor finishes the execution of all pending tasks, it finishes its execution. After you call the shutdown() method, if you try to send another task to the executor, it will be rejected and the executor will throw a RejectedExecutionException exception. The following screenshot shows part of one execution of this example:




There's more...
The ThreadPoolExecutor class provides a lot of methods to obtain information about its status. We used in the example the getPoolSize(), getActiveCount(), and getCompletedTaskCount() methods to obtain information about the size of the pool, the number of threads, and the number of completed tasks of the executor. You can also use the getLargestPoolSize() method that returns the maximum number of threads that has been in the pool at a time.

  • shutdownNow(): This method shut downs the executor immediately. It doesn't execute the pending tasks. It returns a list with all these pending tasks. The tasks that are running when you call this method continue with their execution, but the method doesn't wait for their finalization.
  • isTerminated(): This method returns true if you have called the shutdown() or shutdownNow() methods and the executor finishes the process of shutting it down.
  • isShutdown(): This method returns true if you have called the shutdown() method of the executor.
  • awaitTermination(long timeout, TimeUnit unit): This method blocks the calling thread until the tasks of the executor have ended or the timeout occurs. The TimeUnit class is an enumeration with the following constants: DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, and SECONDS


That's all. Thanks for reading this and if you found this article useful, I would like to see your appreciation in the form of comments.



If you know anyone who has started learning java, why not help them out! Just share this post with them. Thanks for studying today!...

Friday, March 20, 2015

ReadWriteLock example in Java

One of the most significant improvements offered by locks is the ReadWriteLock interface and the ReentrantReadWriteLock class, the unique one that implements it. This class has two locks, one for read operations and one for write operations. There can be more than one thread using read operations simultaneously, but only one thread can be using write operations. When a thread is doing a write operation, there can't be any thread doing read operations.


In this article, you will learn how to use a ReadWriteLock interface implementing a program that uses it to control the access to an object that stores the prices of two books


BookInfo class




Create a class named Reader and specify that it implements the Runnable interface. This class implements a reader of the values of the BookInfo class attributes.



Create a class named Writer and specify that it implements the Runnable interface. This class implements a modifier of the values of the BookInfo class attributes.



Main class




As we mentioned previously, the ReentrantReadWriteLock class has two locks, one for read operations and one for write operations

The lock used in read operations is obtained with the readLock() method declared in the ReadWriteLock interface. This lock is an object that implements the Lock interface, so we can use the lock(), unlock(), and tryLock() methods. 

The lock used in write operations is obtained with the writeLock() method declared in the ReadWriteLock interface. This lock is an object that implements the Lock interface, so we can use the lock(), unlock(), and tryLock() methods.

It is the responsibility of the programmer to ensure the correct use of these locks, using them with the same purposes for which they were designed.When you get the read lock of a Lock interface, you can't modify the value of the variable. Otherwise, you probably will have inconsistency data errors.




If you know anyone who has started learning java, why not help them out! Just share this post with them. Thanks for studying today!...

Producer Consumer problem in Java using wait and notify

A classic problem in concurrent programming is the producer-consumer problem. We have a data buffer, one or more producers of data that save it in the buffer and one or more consumers of data that take it from the buffer.
As the buffer is a shared data structure, we have to control the access to it using a synchronization mechanism such as the synchronized keyword, but we have more limitations. A producer can't save data in the buffer if it's full and the consumer can't take data from the buffer if it's empty




For these types of situations, Java provides the wait(), notify(), and notifyAll() methods implemented in the Object class. A thread can call the wait() method inside a synchronized block of code. If it calls the wait() method outside a synchronized block of code, the JVM throws an IllegalMonitorStateException exception. When the thread calls the wait() method, the JVM puts the thread to sleep and releases the object that controls the synchronized block of code that it's executing and allows the other threads to execute other blocks of synchronized code protected by that object. To wake up the thread, you must call the notify() or notifyAll() method inside a block of code protected by the same object.

In this article, you will learn how to implement the producer-consumer problem using the synchronized keyword and the wait(), notify(), and notifyAll() methods

Storage class
It has two attributes: an int attribute called maxSize and a LinkedList<Date> attribute called list.

Implement the synchronized method set() to store an event in the storage. First, check if the storage is full or not. If it's full, it calls the wait() method until the storage has empty space. At the end of the method, we call the notifyAll() method to wake up all the threads that are sleeping in the wait() method.

Implement the synchronized method get() to get an event for the storage. First, check if the storage has events or not. If it has no events, it calls the wait() method until the storage has some events. At the end of the method, we call the notifyAll() method to wake up all the threads that are sleeping in the wait() method.

Producer and Consumer
Create a class named Producer and Consumer and specify that it implements the Runnable interface. 
Main Class
Sample Output


How it works...
The key to this example is the set() and get() methods of the EventStorage class. First of all, the set() method checks if there is free space in the storage attribute. If it's full, it calls the wait() method to wait for free space. When the other thread calls the notifyAll() method, the thread wakes up and checks the condition again. The notifyAll() method doesn't guarantee that the thread will wake up. This process is repeated until there is free space in the storage and it can generate a new event and store it.

The behavior of the get() method is similar. First, it checks if there are events on the storage. If the EventStorage class is empty, it calls the wait() method to wait for events. Where the other thread calls the notifyAll() method, the thread wakes up and checks the condition again until there are some events in the storage.

If you run this example, you will see how producer and consumer are setting and getting the events, but the storage never has more than 10 events.




If you know anyone who has started learning java, why not help them out! Just share this post with them. Thanks for studying today!...

Thursday, March 19, 2015

UncaughtExceptionHandler in Java

UncaughtExceptionHandler is interface for handlers invoked when a Thread abruptly terminates due to an uncaught exception. Basically, this is a mechanism to catch and treat the unchecked exception thrown in a thread object that what we are going to see in this article.




There are two kinds of exceptions in Java:

  • Checked exceptions: These exceptions must be specified in the throws clause of a method or caught inside them. For example, IOException or classNotFoundException.
  • Unchecked exceptions: These exceptions don't have to be specified or caught. For example, NumberFormatException.

When a checked exception is thrown inside the run() method of a Thread object, we have to catch and treat them, because the run() method doesn't accept a throws clause. When an unchecked exception is thrown inside the run() method of a Thread object, the default behaviour is to write the stack trace in the console and exit the program

Fortunately, Java provides us with a mechanism to catch and treat the unchecked exceptions thrown in a Thread object to avoid the program ending


First of all, we have to implement a class to treat the unchecked exceptions. This class must implement the UncaughtExceptionHandler interface and implement the uncaughtException() method declared in that interface. In our case, call this class ExceptionHandler and make the method to write information about Exception and Thread that threw it. Following is the code:

Now, implement a class that throws an unchecked exception

Now, implement the main class of the example

When an exception is thrown in a thread and is not caught (it has to be an unchecked exception), the JVM checks if the thread has an uncaught exception handler set by the corresponding method. If it has, the JVM invokes this method with the Thread object and Exception as arguments.
If the thread has not got an uncaught exception handler, the JVM prints the stack trace in the console and exits the program.


There is more....
The Thread class has another method related to the process of uncaught exceptions. It's the static method setDefaultUncaughtExceptionHandler() that establishes an exception handler for all the Thread objects in the application. 

When an uncaught exception is thrown in Thread, the JVM looks for three possible handlers for this exception.

First, it looks for the uncaught exception handler of the Thread objects as we learned in this recipe. If this handler doesn't exist, then the JVM looks for the uncaught exception handler for ThreadGroup of the Thread objects as was explained in the Processing uncontrolled exceptions in a group of threads recipe. If this method doesn't exist, the JVM looks for the default uncaught exception handler as we learned in this recipe.

If none of the handlers exits, the JVM writes the stack trace of the exception in the console and exits the program.




If you know anyone who has started learning java, why not help them out! Just share this post with them. Thanks for studying today!...

Sunday, February 22, 2015

Cloning Objects in Java

In Java, objects are manipulated through reference variables, and there is no operator for copying an object—the assignment operator duplicates the reference, not the object. The clone() method provides this missing functionality. In this article, we look into the basic of cloning in Java and types of cloning such as shallow and deep cloning. Also, it disadvantages  and  what are the alternative approach to do the cloning in Java.




Java does not provide an automatic mechanism to clone (make a copy) an object. Recall that when you assign a reference variable to another reference variable, only the reference of the object is copied, not the content of the object. 
Cloning an object means copying the content of the object bit by bit. If you want objects of your class to be cloned, you must re-implement the clone() method in your class. Once you re-implement the clone() method, you should be able to clone objects of your class by calling the clone() method. The declaration of the clone() method in the Object class is as follows:

protected Object clone() throws CloneNotSupportedException


You need to observe few things about the declaration of the clone() method.

  • It is declared protected. Therefore, you will not be able to call it from the client code. The following code is not valid:Object obj = new Object();Object clone = obj.clone(); // Error. Cannot access protected clone() method.This means you need to declare the clone() method public in your class if you want the client code to clone objects of your class.
  • Its return type is Object. It means you will need to cast the returned value of the clone() method. Suppose MyClass is Cloneable. Your cloning code will look as
    MyClass mc = new MyClass();
    MyClass clone = (MyClass)mc.clone(); // Need to use a cast

You do not need to know any internal details about an object to clone it. The clone() method in the Object class has all the code that is needed to clone an object. All you need is to call it from the clone() method of your class. It will make a bitwise copy of the original object and return the reference of the copy.
The clone() method in the Object class throws a CloneNotSupportedException . It means when you call the clone() method of the Object class, you need to place the call in a try-catch block, or re-throw the exception.You have the option not to throw a CloneNotSupportedException from the clone() method of your class

The following snippet of code is placed inside the clone() method of your class, which calls the clone() method of the Object class using the super keyword:
One important thing that you must do is add an "implements Cloneable" clause in your class declaration. Cloneable is an interface declared in the java.lang package.Otherwise, you will get a runtime error when you call the clone() method on the objects of your class.

Example

Once your class implements the clone() method correctly, cloning an object of your class is as simple as calling its clone() method
At this point, there are two separate objects of the Burger class. The veg variable references the original object and vegClone variable references the clone of the original object. The original as well as the cloned object hold the same value of 100. However, they have separate copies of the value. If you change the value in the original object, for example, vegClone.setBurgerPrice(200), the value in the cloned object remains unchanged. Let see the tester class
From Java 5, you need not specify the return type of the clone() method in your class as the Object type. You can specify your class as the return type in the clone() method declaration. This will not force the client code to use a cast when it call the clone() method of your class.
With the above declaration for the clone() method, you can write code to clone an object as follows. Note that no cast is needed anymore

The standard pattern for making a class cloneable is:
  1. Implement Cloneable
  2. Override the clone() method and make it public
  3. In clone() call super.clone() and then copy any mutable object's state
You should not create a new object using new. The proper way is to call super.clone() for a new instance. Object's clone() is special and will create a new copy of the object and copy its primitive fields and references.

Shallow Cloning
An object may be composed of another object. In such cases, two objects exist in memory separately—a contained object and a container object. The container object stores the reference of the contained object. When you clone the container object, the reference of the contained object is cloned. After cloning is performed, there are two copies of the container object; both of them have references to the same contained object. This is called a shallow cloning because references are copied, not the objects. The clone() method of the Object class makes only shallow cloning, unless you code it otherwise.


Example ShallowClone 

An object of the ShallowClone class is composed of an object of the Burger class. The code in the clone() method of the ShallowClone class is the same as for the clone() method of the Burger class. The difference lies in the type of instance variables that are used for the two classes. The Burger class has an instance variable of primitive type int, whereas the ShallowClone class has an instance variable of the reference type DoubleHolder. When the ShallowClone class calls the clone() method of the Object class (using super.clone()), it receives a shallow copy of itself. That is, it shares the Burger object used in its instance variable with its clone.

Following code test an object of the ShallowClone class and its clone. The output shows that after you make a clone, changing the value through the original object also changes the value in the cloned object. This is so because the ShallowClone object stores the value in another object of the Burger class, which is shared by both the cloned and the original objects.



Deep Cloning
When the contained objects are copied rather than their references during cloning of a compound object, it is called deep cloning. You must clone all the objects referenced by all reference variables of an object to get a deep cloning.
A compound object may have multiple levels of chaining of contained objects. For example, the container object may have a reference of another contained object, which in turn has a reference of another contained object and so on. Whether you will be able to perform a deep cloning of a compound object depends on many factors. If you have a reference of a contained object, it may not support cloning and in that case, you have to be content with shallow cloning. You may have a reference of a contained object, which itself is a compound object. However, the contained object supports only shallow cloning, and in that case again, you will have to be content with shallow cloning.

In a deep cloning, you need to clone all objects referenced by all reference instance variables of an object. You must perform a shallow cloning before you can perform a deep cloning. The shallow cloning is performed by calling the clone() method of the Object class. Then you will need to write code to clone all reference instance variables.

Example DeepClone 

If you compare the code in the clone() method of the ShallowClone and DeepClone classes, you will find that for deep cloning you had to write only one extra line of code.


copy.burger = (Burger)this.burger.clone();

What will happen if the Burger class is not cleanable? In that case, you would not be able to write the above statement to clone the holder instance variable. You could have cloned the burger instance variable as follows:

copy.burger = new Burger(this.burger.getValue());

The goal is to clone the burger instance variable and it does not have to be done by calling its clone() method



Clone Method
In order for implementing the Cloneable interface to have any effect on a class, it and all of its superclasses must obey a fairly complex, unenforceable, and largely undocumented protocol. It creates an object without calling a constructor. The general contract for the clone method is weak. Here it is, copied from the specification for java.lang.Object:



Tip
Using the clone() method of the Object class is not the only way to make a clone of an object. You can use other methods to clone an object. You may provide a copy constructor, which accepts an object of the same class and creates a clone of that object. You may provide a factory method in your class, which may accept an object and returns its clone. Another way to clone an object is to serialize it and then deserialized it.

The copy constructor approach and its static factory variant have many advantages over Cloneable/clone:

  • They do not rely on a risk-prone extralinguistic object creation mechanism Where as in clonealbe, In order for implementing the Cloneable interface to have any effect on a class, it and all of its superclasses must obey a fairly complex, unenforceable, and largely undocumented protocol. The resulting mechanism is extralinguistic: It creates an object without calling a constructor.
  • They do not conflict with the proper use of final fields where in cloneable, If a class is not final, `clone` has to return the most derived class for which it was called. That can't work with a constructor, because `clone` doesn't know which one to call. If a class is final, it can't have any subclasses, so there's no danger in calling its constructor when cloning.
  • They do not require the client to catch an unnecessary checked exception, where it require clonealbe require the client to handle the exception.
  • They provide a statically typed object to the client.



If you know anyone who has started learning java, why not help them out! Just share this post with them. Thanks for studying today!...

Thursday, February 5, 2015

Assertions in Java

When creating application programs, you assume many things. However, often it happens that the assumptions don’t hold, resulting in an erroneous condition. The assert statement is used to check or test your assumptions about the program. In this article, we try to understand how and when to use assert keyword in Java.

There are many reasons why you should add assertions to the program. One reason is that it helps find the problems early; when you check your assumptions in the program, and when any of them fail, you immediately know where to look out for the problem and what to fix. Also, when other programmers read your code with assertions, they will be in a better position to understand the code because you are making your assumptions explicit using assertions.


The keyword assert provides support for assertions in Java. Each assertion statement contains a Boolean expression

  • If the result of the Boolean expression is true, it means the assumption is true, nothing happens. 
  • However, if the Boolean result is false, then the assumption you had about the program holds no more, and an AssertionError is thrown. 

Remember that the Error class and its derived classes indicate serious runtime errors and are not meant to be handled. In the same way, if an AssertionError is thrown, the best course of action is not to catch the exception and to allow the program to terminate. After that, you need to examine why the assumption did not hold true and then fix the program.


A simple assertion is a statement of the form:

assert logical_expression;

Here, assert is a keyword, and logical_expression is any expression that results in a value of true or false . When this statement executes, if logical_expression evaluates to true , then the program continues normally. If logical_expression evaluates to false , the program is terminated with an error message starting with: java.lang.AssertionError. This is followed by more information about where the error occurred in the code. When this occurs, the program is said to assert.


Assert Statement
Assert statements in Java are of two forms:

  • assert booleanExpression;
  • assert booleanExpression : "Detailed error message string";

It is a compiler error if a non-Boolean expression is used within the assert statement.

Example
In this program, you are checking if the value of i is < 0; you are using the expression –i to convert it to a positive value. Once the condition check if (i < 0) is completed, the value of i cannot be negative, or that is your assumption. Such assumptions can be asserted with an assert statement.
The program will run fine if the Boolean expression (i >= 0) evaluates to true. However, if it evaluates to false, the program will crash by throwing an AssertionError.
Output:
Yes, this program executed successfully without throwing any exceptions.

Is there any value of i for which the condition will fail? Yes, there is! If the value of i is a minimum possible value of integer, then it cannot be converted into a positive value. Why? Remember that the range of integers is -2^31 to 2^31 – 1, so the integer values the value of i as –2147483648 to 2147483647. In other words, the positive value 2147483648 is not in the range of integers. So, if the value of i is –2147483648, then the expression -i will overflow and again result in the value –2147483648. Thus, your assumption is not true.

int i = Integer.MIN_VALUE;

Output

Enable/Disable Assertion
You saw that assertions are disabled at runtime; to enable assertions at runtime, use an -ea switch.To disable assertions at runtime, use a -da switch. If assertions are disabled by default at runtime, then what is the use of -da switch? There are many uses. For example, if you want to enable assertions for all classes within a given package and want to disable asserts in a specific class in that package, then a -da switch is useful.



How Not to Use Asserts
The key to understanding assertions is that they are useful for debugging and testing applications, and assertions are meant to be disabled when the application is deployed to end users.

  • Don’t use assertions for validating input values or for validating arguments to public methods. For signaling such runtime failures, use exceptions instead.
  • Don’t use assertions to check conditions that are required for the correct functioning of the application. Since assertions are disabled by default at runtime, the application will not function correctly when the asserted conditions are not present in the code.
  • The Boolean expressions given inside assert statements should not have side effects— modifying variable values, printing values to console, etc. In other words, the functioning of the application should remain the same no matter if assertions are enabled or disabled.


If you know anyone who has started learning java, why not help them out! Just share this post with them. Thanks for studying today!...