Java 8 Streams – Streams in Java With Examples

Java 8 Streams – Streams in Java With Examples

What are Streams?

  •  Sequence of objects supporting multiple methods.

Features:

  • Stream is not a data structure and does not store elements.
  • Source of stream remains unmodified after operations are performed.
  • Streams perform operation over the collection but actually does not modify the underlying collection.
  • Laziness, evaluates only when requried. (When Terminal operation is identified)
  • Visitation of elements only once, to revisit we need new stream. If same stream used it throws IllegalStateException.

Laziness:

  • Intermediate operations are not evaluated until terminal operation invoked.
  • Each intermediate operation creates a new stream and process and returns stream.
  • When terminal invoked, traversal begins and operations are performed one by one.
  • Parallel streams does not evaluate only by one but simultaneously based on available ones.

Intermediate and Terminal Operations:

  • Every stream will perform Intermediate and Terminal Operations.
  • There can be any number of Intermediate operations but only one Terminal operation
  • Streams will not process until it reaches the Terminal operation, once it reaches Terminal operation then only stream processing will start.
  • It is mandatory for a stream to have Terminal operation for the stream to process or Streams will not process.
Intermediate Operations Terminal Operations
filter toArray()
map Collect
flatmap Count
distinct reduce
sorted forEach
limit forEachOrdering
skip min
peek max
Anymatch
allmatch
nonematch
findfirst

findany

 

let us see some examples of some Intermediate and Terminal operations,

Let us create a main method to populate the object,

Output:

==================== STUDLIST========================
[Student [studentName=Alpha Student, studentSubjects=[Computers, Information Technology]], Student [studentName=Beta Student, studentSubjects=[Java, Spring]]]

 



Map vs FlatMap:
Map
produces one output value for each input value

FlatMap takes one input value and provides arbitrary number of values. In short helps to flatten a Collection<Collection<T>> into a Collection<T>.

Now let us see an example,

Output:



Distinct:
To get unique values from the collection.

Output:



Limit:
Limit result to certain number of records. In the below example we are limiting the total number of records to 3.

Output:



Peek:
When we have to view any value in the middle of Stream operations, We can use peek.

Output:



Skip:
Skips the specific number of elements. In the below example, first 3 elements are skipped and values are printed from 4th element.

Output:



Sorting:
We can do sorting using Streams, reverse sorting and natural order sorting. We had done reverse and natural order sorting in the below example.

Output:



Count:
To count the number to elements in the collection.

Output:


Min And Max:
To find the Minimum and Maximum from collection. Below are few examples,

Output:

 


ForEach vs Stream.forEach:
Both are used for Iterating a collection, The difference between them are,

forEach – Does not maintain order
Stream.forEach – Maintains Order

Output:

Reduce:
Used to perform operations are multiple values and returns a single result. In the below example we have used addition.

Output:



Filter, FindAny, FindFirst, AnyMatch and AllMatch:
Filter:
Similar to if condition to search or find any value
FindAny:
Returns an object which may or may not contain a non-null value
FindFirst:
Finds the first element when it is matched
AnyMatch:
Return true if atleast one element matches the condition
AllMatch: 
Returns true if all elements in the stream are matched (satisfies the condition)

 

 Complete Code:

 

 

 

Integrate Shell with SpringBoot – SpringBoot Shell

Integrate Shell with SpringBoot – SpringBoot Shell:

What is a Shell?
Shell is an environment where user provides the input and it program will execute and returns the result. We can run shell with commands or scripts.

SpringBoot provides us a way to integrate this shell environment within our application. We can easily build a shell application just by including a dependency which has all Spring shell jars. We can also declare our own commands in the application to executing it.

Dependency for Shell in SpringBoot:

The above dependency will download Springshell jars.

Lets create a main class for springboot application,

Now let us create our shell class,

@ShellComponent is an stereotype kind of annotation similar to @Component, @Service etc. to make springboot to understand this class is Shell Component.

Now let us write a method for shell to execute,

@ShellMethod – This annotation is used to explicitly define the custom shell command.
We have written a method which takes String as a parameter and will return the String with – “Shell Command Executed” followed by the parameter String.

Let us check this by running our SpringBoot application,

Once we deploy the application, we will get CLI for entering shell command in our console. When we give help,

shell:>help

We can see the available in-build commands and the method which we have created.

display – method name
value – Description for the method which we have provided along with @ShellMethod annotation.

Now let us execute the Shell Command,

We have to give the method name – display followed by the parameter. Here we given display and parameter – ‘Success’ where we get the output – Shell Command Executed Success.

Let us see another example to perform addition of 2 numbers,

Here we have written a method to pass 2 integer parameters and returning addition of 2 values.

let us try to execute our shell command,

We have executed our add method, we have declared in 2 different ways,

We have used positional parameter concept, without giving parameter name we directly passed the values for a and b. Suppose if we have to pass based on parameter we can use the 2nd way to executing the method,

add –b 2 –a 1.

Now let us see another method to pass String parameter with default value.

We have to declare with @ShellOption value,
Here we have mentioned defaultValue for the parameter s, so if we try to execute this command even without any parameter it will return with default value.

Here we have called default-display without any parameter, it gives the default value. With parameter it gives the parameter value instead of default value.

We can also perform validation for the parameters. Let us see an example below.

Here we have 2 methods, one to check with Integer with size minimum of 2 and maximum of 4. Another method to check String is not null.

Now let us execute the commands in shell,

From the above screenshot, we can confirm the validation is done.

There is also a way where we can change the text that is being displayed in console – shell:> – we can replace this text. Let us see how to change,

We need to implement the PromptProvider interface and need to override the method – getPrompt().

We are returning new AttributedString(“String”, String start index,String end Index);

In our code we have used the String – “ShellCommandPrompt:>”. Now let use run our SpringBoot application and see our changes,

The shell:> is changed to ShellCommandPrompt: from our Configuration.

Please find the complete code below,

ShellApplication.java

ShellOperations.java

ShellPromptProvider.java

pom.xml

 

What happens if we do not override hashcode() and equals() in hashmap?

What happens if we do not override hashcode() and equals() in hashmap?

In this post, let us understand what is the use of equals() and hashcode(), why it is important to override them and what will happen if we dont override them

To understand this post, it is expected to have knowledge of Internal Working of HashMap.

If not aware of internal working of hashmap, lets have a quick overview.

Important Points of HashMap:

  • HashMap has Key and Value pairs.
  • HashMap is not Synchronized (i.e. Not Thread Safe)
  • HashMap has no guarantees as to the order of the map
  • HashMap does not guarantee that the order will remain constant over time.
  • HashMap allows only one Null Key, Which will always be stored at 0th position in the bucket
  • HashMap can have multiple null values, but only one null key is allowed
  • HashMap can be Synchronized externally using Collections.synchronizedMap(HashMap)

Internal Working of HashMap: (Quick Summary)
So How does HashMap works Internally?
HashMap has the implementation of Map Interface.  HashMap has key and value pairs.

The initial capacity of HashMap is 16 and where as load factor is 0.75.

What is Initial Capacity and LoadFactor?
The initial capacity is the number of buckets in the hashtable and the load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased.

When we try to put a Key and Value within HashMap, first the equals method will check whether both objects are equal and then it hashes and find the bucket where to insert this Key and Value. If both the objects are equal, it will override the already existing Object in Bucket.
In Short,  equals() will help us to identify if the object is unique and HashCode helps us to identify the bucket in which the values has to be Stored.

Now Let us see this with an Example,

For the below Example, we are going to create Employee class and another Main class.

We have created an Employee class, Now let us create a main method

equals() and hashcode() – Not Overridden:

The above code, we haven’t implemented equals() and hashcode() method. Let us the what output our code gives,

Though both objects are equal() since we haven’t overridden the equals(), so it considers both the objects as unique keys. We also haven’t overridden the hashcode(), so even when both objects are same, their hashcode is different.

How it works without Overriding equals() and hashcode()?

From the output, first it compares two objects (eventhough they are equals, since we have not overridden the equals()) it shows both the objects are not equals and will be considered as Unqiue Keys and with values.

From the hashing, it goes to different buckets – duplicate entries for same object.

Override equals() and Not hashcode:

Now let us Override only Equals() method,

 

Now after overriding equals method, let use slightly modify our main method,

Now after overriding only equals() method, we can see both objects are compared and identified as equals objects (Both Objects are  Equal: true)

But here the problem is, though both the objects are equal() the hashcode() is different and so the both objects will be stored in different buckets.

If both objects are equal and if it points to same bucket then the value will be overridden.

Override hashcode() and Not equals():

When we run the code,

Since we have overridden only hashcode() and not equals method() –> The objects comparison becomes false, means the objects are unique. So even though the hashcode points to same bucket, the objects are considered as unique keys and both the values will be stored in the bucket.

override both equals() and hashcode():

Now let us run the above code and see,

Since we have overridden the equals() and hashcode(), when inserting in map — It has identified both objects are equal and both has same hashcode values. So when trying to insert into the bucket, only one value will be inserted that is the reason we have only one element in hashmap (Key is: Employee@13665 Value is: Two)

Complete Code:

 

How does hashmap work Internally | Internal Working of HashMap

How does hashmap work Internally – Explained:

In this post, let us see how hashmap works internally – How the elements are added and retrieved from buckets.

Features of HashMap:

  • Implementation of Map Interface – With Key and Value pairs
  • No order of maps, also order of map changes over time
  • Accepts one null key and multiple null values
  • Keys should be unique and cannot have duplicates
  • Unsynchronized i.e. Not Thread Safe
  • Initial capacity is 16 and load factor is 0.75
  • Synchronized externally using Collections.SynchronizedMap(hashmap)

What is Initial Capacity and Load factor?

Initial Capacity is number of buckets in hashtable, that i.e. by default HashMap provides 16 buckets when created, we can define number of buckets required when creating the HashMap.

Load Factor indicates when a certain capacity of elements are populated in HashMap, it size will increaase. Load factor decides how much of capacity should be filled before increasing the size of hashmap.

https://www.youtube.com/watch?v=nff4KWFtwW0&feature=youtu.be

HashMap Creation:

  • public HashMap()
  • public HashMap(int initialCapacity)
  • public HashMap(int initialCapacity, float loadFactor)
  • public HashMap(Map<? extends k, ? extends v> m) –> Cretes new HashMap with the specified Map.

To understand how hashmap works internally, let us consider we have an employee model class with a variable employee name,

Let us create employee object and put the employee object as key in HashMap and let us see how it gets inserted into HashMap.

 

From the above,

We have created 3 employee objects – e1, e2 and e3 with names Alpha, Beta and Charlie

Then we have put these values in hashmap with employee object as Key

HashMap<Employee, String> hm = new HashMap<Employee, String>();

hm.put(e1, “One”);
hm.put(e1, “Two”);
hm.put(e1, “Three”);

Now we have inserted the values into HashMap, we can see how they are populated in Buckets.

For our example, let us consider the hashcode values of

e1 – 756475 and it puts in bucket 2
e2 – 897865 and it puts in bucket 14
e3 – 756909 and it puts in bucket 2 again

First it checks the bucket, if any values are present. Since we do not have any values, it inserts the value in bucket 2.
It will insert hashcode first , i.e. 756475, next it will insert the key of HashMap – here the key is e1, then the value “One”, and last will be the pointer to next node. For now it will be null as no other elements are present to be populated in bucket.

Second we have the hashmap with element key e2 and value “Two”. It will check the bucket 14 and since no value is already present, it will populate the values in bucket 14.
hashcode of e2 – 897865, then the element Key, then element value, followed by the next value pointer, which is null for now.

Third, we have the hashmap with element key e3 and value “Three”. It will check for the bucket 2, and we have a value in it.

Here comes the key role for equals() method, it will check whether the e3 Key is unique when compared to e1. (e3.equals(e1)). It will return false as both objects are not equal. Then from the node which is kept as null when inserting first element, will point to next element i.e. e3.

In the same bucket as second entry, e3 will be populated with hashcode –  756909, Key – e3, value – Three and next will be kept as null until we get another value to be populated.

e1 entry which had null next now will point to e3 entry.

 

What happens when we insert duplicate Key?

Here we have created another employee object e4, with same value as of e1.

Employee e4 = new Employee(“Alpha”);

hm.put(e4, “Four”);

How as we discussed, it will calculate the hashcode for the object e4. The hascode is 756475 and it points to bucket 2.

But the bucket 2 already has more records available. So first will check for hashcode, if the inserting record hashcode and available record hashcode matches, then it will compare the Key. This is where equals() plays an important role.

In the above case, e1.equals(e4) which will return true as both objects are equal. Then the values of object e1 will be replaced with values of e4.

so now the hashbucket first entry will be of e4 values,

Important Keypoints:

  • HashMap uses hashcode() to identify the bucket where the record to be inserted
  • If a record is already available in the bucket, it will check for key (to check uniqueness) with equals() method, if it return true then the record will be replaced. If it false, new record will be inserted.
  • When more than one record is available in the bucket, it will have a next node which will point to the next available record in the bucket.

How does get() method work in HashMap?

Now let us try to retrieve an element from hashmap, let us retrieve e3,

hm.get(e3);

Now hashmap will use hashcode() and will identify the bucket in which element might be present. Next it will go to the bucket (In this case 2) and finds more than one record is available.

Now it will compare the key, if both the keys are matched then it will retrieve the value.

 

 

So When we try to get e3, first it will calculate the hashcode

hashcode() for Key e3 : 756909 and based on indexing to identify the bucket, it is calculated to be Bucket 2.

But Bucket 2, already has more than one record. Next the calculated hashcode will be compared to the inserted record in hashmap bucket 2. First it will compare 756909 with first record in hashmap that is 756475. Both are not equal, next will check the next node. Here the next node is pointing to another record. So it will go to the next record and will compare the hashcodes. 756909 and next record’s hashcode 756909 both are equal. Next will take the key of that record from bucket 2 and will compare with the key user requested. In this case, e3.equals(e3) which will return true.

Since both objects are equal and hashcodes are matching, that record will be retrieved from hashbucket and given to the user. This is how get method works.

Key Note:

If two objects are equal, their hashcode will always be same
If two hashcodes are same, that doesn’t mean both objects are equal.

Strings are Immutable | StringBuilder | StringBuffer

Strings are Immutable | StringBuilder | StringBuffer:

In this post, let us discuss about Strings, why Strings are immutable where as StringBuilder and StringBuffer are mutable.

 

What is Immutability?

When we assign a value to a String variable, that value can never be changed. That is known as immutability.

Strings can be created in 2 ways,

String S1 = “One”;

String S1 = new String(“One”);

What is the difference between these two ways of String creation?

String creation Way 1:

First let us see the type 1, i.e. String S1 = “One”;

For better understanding, let us create 3 strings

In general, Whenever a String is created all the values will be stored in StringPool. Here we have created 3 Strings so all these values – “One”, “Two” and “One” should be stored in StringPool.

Let us see how these above String values are Stored in StringPool.

 

As we can see the values – “One” and “Two” are stored in StringPool but another value of String S3 = “One” is not stored in StringPool. What actually happened?

When the values are Stored in StringPool when Strings are created in above mentioned way, When two or more strings has the same value only one of that such value will be stored in StringPool and the address of that value in StringPool will be referenced to String Variables.

So from above, since S1 and S3 has same value only one of such value is stored in StringPool and the address Addr1 will be referenced to S1 and S3

So the String variables will point to,

S1 = Addr1
S2 = Addr2
S3 = Addr1

How does “==” Work when Strings are created in above mentioned way?

The “==” works by comparing the address of the String variable rather than comparing the exact value of Strings. So in this case if we try to compare (S1==S3), Since both has same address it will
return True.

What if we concatenate the String? Will the value be replaced?

As we discussed, Strings are immutable. That is, once a value has been created that value will never change.
Consider this example,

If we concatenate String S1, what will happen?

S1 = “One” + “Three”;

Will the above statement replace the value One in StringPool? The answer is No.

Now we have concatenated the String, How the values will be at StringPool?

The new concatenated value will be inserted into StringPool and the String Variable S1 will point to new inserted value address – Addr3, Where as the value “One” remains unchanged.
This is the reason Strings are said to be Immutable.

Second way of Creating a String:

Another way of creating a String is using new Keyword, Let us create 3 strings for our understanding.

So we have created 3 Strings – S1,S2 and S3 and assigned the value – “One”, “Two” and “One” using new keyword.

How are these values stored in StringPool?

As you can see the difference, the value “One” is inserted again for the variable S3. Why?

Because the way we created String, We have used new keyword. When we create a String using new keyword, each String is considered as new value and it will be Stored in StringPool even though the same value might be available in StringPool.

So here, The String S1 will have Addr1 pointed to it, S2 will have Addr2 and S3 will have Addr3 – even though S1 and S3 has same value, since we used new keyword to insert the String – it inserted the “One” as new value and new address is given.

How does “==” Work when Strings are created in second String creation way?

Since each value is created newly and inserted in StringPool, The result will always be false for S1==S3 as both S1 and S3 have different addresses.

Why is StringBuilder and StringBuffer are mutable?

StringBuilder internally extends AbstractStringBuilder, it has a value which has an underlying working of Array. Since Arrays are mutable and StringBuilder is an Array wrapped class, it is mutable.

What if we perform Concatenation in StringBuilder?

It will not create a new value, instead it will replace the existing value with newly concatenated value

So what is the difference between StringBuilder and StringBuffer?

The only difference between StringBuilder and StringBuffer is – StringBuilder is not Synchronized (i.e. Not Thread Safe) where as StringBuffer is Synchronized (i.e.Thread Safe)

Performance:
When considering the performance, StringBuilder is faster than StringBuffer because, StringBuilder is not synchronized.