Showing posts with label Exploring Java 8. Show all posts
Showing posts with label Exploring Java 8. Show all posts

Monday, March 22, 2021

Exploring Java 8 : Streams terminal functions


Hello there techie Ninja's, Hope you are doing well. Today, in this blog we would be learning about the terminal operations in java 8 streams. You might have seen in previous blogs that intermediate operation flows the data, transform it but it again produces new streams. If you want to collect the data from streams to normal collection class or another format, you need to use the terminal operation.  One of the terminal functions we have seen till now is Collectors.collect(). Yes, it is a terminal function. Apart from this one, java streams have a few more terminal functions, which you can use as per need. Let's check this out.

Terminal Functions/Operations in Java 8 Streaming API

Here is the list of terminal function available
  • allMatch
  • anyMatch
  • noneMatch
  • count
  • forEach
  • min
  • max
  • reduce
  • collect


allMatch(), anyMatch(), noneMatch()

These 3 termination functions accept a predicate and return a boolean value. These functions mainly used to evaluate a condition on the elements of a stream and return true or false based on the condition. The point to note here is that it is a termination function. once you invoke it on stream, the stream will no longer be opened. it would be terminated once you call the termination function. let's have a look at the below example

Signature :
boolean anyMatch(Predicate<? super T> predicate);
boolean allMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);

Example :
package org.java4ninja.exploringjava8.streams;

import java.util.Arrays;

public class TerminalOperations {
public static void main(String args[]) {
// return true if all words have minimum 2 or more characters
// expected to match the condition by all elements of streams
boolean doesAllWordsHas3Letters = Arrays.asList(
"ANT",
"BAT",
"CAT",
"DOG",
"EAT",
"FAT").stream().allMatch((s) -> s.length() >= 2);

// return true if at least one cat exist
// expected to match the condition by at least by one element
boolean isCatPresentInStream = Arrays.asList(
"ANT",
"BAT",
"CAT",
"DOG",
"EAT",
"FAT").stream().anyMatch((s) -> s.equalsIgnoreCase("cat"));

// return true if none of the element matches the condition
// expected to not to match
boolean noneOfTheElementMatchCondition = Arrays.asList(
"ANT",
"BAT",
"CAT",
"DOG",
"EAT",
"FAT").stream().noneMatch((s) -> s.length() > 3);
System.out.println(noneOfTheElementMatchCondition);
}
}

min() and max()

This terminal operation returns the smallest and biggest element in the stream. min() function return the smallest element whereas max() function return the biggest element. Both of them take the comparator as an input and return the Optional of the type. When Stream is empty this function will return Optional empty().

Signature:
Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);

Example :
package org.java4ninja.exploringjava8.streams;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

public class TerminalOperationMinMax {

@AllArgsConstructor
@ToString
@Getter
private static class Employee {
private int id;
private String name;
private int age;
}

public static void main(String args[]) {

List<Employee> listOfEmployees = Arrays.asList(
new Employee(1, "Anil", 29),
new Employee(2, "Joe", 21),
new Employee(3, "Jane", 35),
new Employee(4, "Bob", 26)
);

Employee youngestEmployee = listOfEmployees
.stream()
.min(Comparator.comparing(Employee::getAge))
.get();

System.out.println("Youngest Employee : " + youngestEmployee);

Employee eldestEmployee = listOfEmployees
.stream()
.max(Comparator.comparing(Employee::getAge))
.get();

System.out.println("Eldest Employee : " + eldestEmployee);
}
}

count(),  forEach() and reduce()

count terminal function counts the number of elements in the stream and returns the long value. 

forEach terminal function iterate over the element of the streams. forEach is a terminal function don't expect you will get the stream back from forEach function. 

reduce is a reducer function that returns a single value representing the collection. if you have seen the map-reduce program, where map operation transforms the data and reduces operation reduce it to a single figure. reduce() function is the reducer part of a map-reduce program in the stream.

Signature
long count();
void forEach(Consumer<? super T> action);
T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);


Example
package org.java4ninja.exploringjava8.streams;

import java.util.Arrays;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

public class TerminalOperationCountForEachReduce {

@AllArgsConstructor
@ToString
@Getter
private static class Employee {
private int id;
private String name;
private int age;
}

public static void main(String args[]) {

List<Employee> listOfEmployees = Arrays.asList(
new Employee(1, "Anil", 29),
new Employee(2, "Joe", 21),
new Employee(3, "Jane", 35),
new Employee(4, "Bob", 26)
);

long count = listOfEmployees.stream().count();
System.out.println("There are " + count + " employees in office");

System.out.println("========= Employee Detaills =======");
listOfEmployees
.stream()
.forEach( eachEmployee -> {
System.out.println( eachEmployee.toString());
});

Integer combinedAgeOfCompany = listOfEmployees
.stream()
.map(Employee::getAge)
.reduce((firstAge, secondAge) -> firstAge + secondAge)
.get();

System.out.println("Combined Age of Company is " + combinedAgeOfCompany);
}
}

collect()

It is the most widely used terminal operation on stream. It takes Collector as an input and returns collection in various formats. We would be going to see the collection with most of the use cases in the next blogs. So we keep this topic for the next blog


I hope you have enjoyed this tutorial. Please let me know your comments, suggestion, and improvements I will try to improve my blog. 

Till then, Good Bye Happy Coding !!!

Sunday, March 14, 2021

Exploring Java 8 : Internal working of Streams


Hello there techies, Hope you are doing good. Welcome to Java4Ninja and Exploring Java 8 Series. Today in this blog we would be talking about the Java 8 streams. it is very essential to understand the way streams work. In order to get the benefit of parallel processing, one should be able to understand how element flows in the streams. 

Since by now you must have basic knowledge of Streams, (I am assuming that you have completed the previous 2 lessons; Introduction to Streams and Intermediate operations in Streams)


Can you tell me what is the output of the below code snippet?

public class StreamApiElementOrder {
public static void main(String args[]) {

Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.stream()
.peek(i -> System.out.println("before any operation: " + i))
.filter(i -> i % 2 == 0)
.map(i -> i * 2)
.limit(3)
.collect(Collectors.toList());
    }
}
Output :

before any operation: 1
before any operation: 2
before any operation: 3
before any operation: 4
before any operation: 5
before any operation: 6


Shocked !! What happened with 7, 8, 9, and 10? Why they did not get printed?

Most of you who are familiar with the Streams would know the reason, but others who are learning Streams for the first time would not get this. and that is why this lesson is important for them. 

Stream uses a pull-based approach for processing any stream. if you did not write any termination operation in the above example like collect(), you won't get any result in the console. Why is it so? because terminal operations are the ones that are requesting elements from streams via pipeline. Now You must be questioning what is the pipeline? the pipeline is nothing but the arrangement of all the intermediate operations before any terminal operation. every single element would get fetch from the stream, by the terminal operators using the pipeline. 

So in the above example, terminal operation collect() requested elements from the stream, so the first element gets served. While serving you saw the message "before any operation: 1". now on element 1, it applies the filter, since our filter is expecting an even number, this element was filtered out from the result. and collector gets no element. it requests for the next element, so the 2nd element gets served, and you saw the message "before any operation: 2". since 2 is an even number, it gets passed to the next step in the pipeline, i.e. double the number. now the number becomes 4 and it gets passed to further intermediate operation i.e. limit(). the limit is tracking the number of elements needed to be passed through it. once it found that 3 elements have been pass through it. it will give the end signal to the collector, and the collector will not request more elements.

I believe now you must have understood why 7, 8, 9, and 10 did not get printed. By the time collector requested the 6th data, the limit intermediate operation found that they have got the 3 even numbers. and it sends a terminal request to the collector. and collector did not request any further elements from the stream.

Attaching here a jpeg representation of the streams pipeline for the above example






Please let me know your suggestion, thoughts, and question. This would help me to improve myself and my blog. Till then, Thank you Good Bye and Happy Coding



Saturday, March 13, 2021

Exploring Java 8 : Intermediate Streams Operations


Hello there techie Ninja, Hope you are doing good. Welcome to Java4Ninja Blog. Today in this blog we would be exploring some intermediate operations that can be performed on streams. I hope you went through my last blog "Introduction to Streams API". If you are a beginner to java streams I would recommend you to read the previous blog, which would clear the basics about streams.

Following are the few Intermediate operations available on Java Streams

  • map
  • filter
  • flatMap
  • distinct
  • sorted
  • peek
  • limit
  • skip

Before we dig into those operations, I would like to tell you that, each of those methods returns a new Stream reference. Each of the intermediate operations creates a new streams object, that's why you can take advantage of method chaining and can write concise and easy-to-read code.

map() operation

map() operation accepts a function Functional Interface Lamdba and it perform transform operation. use case of map() operation would be whenever you wanted to transform any data from one data type to another data type you can use the map operation. 

Syntax :

Stream<R> map(Function<? super T, ? extends R> mapper)

Example :
package org.java4ninja.exploringjava8.streams;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

class Employee {
private String firstName;
private String lastName;

public Employee(String firstName, String lastName) {
this.firstName =firstName;
this.lastName = lastName;
}

@Override public String toString() {
return "Employee{firstName='" + firstName + "\' lastName='" + lastName + "\'}";
}
}

public class StreamsIntermediateExample {
public static void main(String args[]) {
List<String> listOfEmployeeNames = Arrays.asList("Will Smith", "Smith Jones",
"Cierra Vega", "Alden Cantrell", "Thomas Crane");

// function which input the string and convert the string to the object of Employee
Function<String, Employee> createEmployeeFromName = (name) -> {
String firstName = name.split(" ")[0];
String lastName = name.split(" ")[1];
return new Employee(firstName, lastName);
};

List<Employee> listOfEmployeeObjects = listOfEmployeeNames
.stream()
.map(createEmployeeFromName)
/* more concise way of writing
/*.map((name) -> {
String firstName = name.split(" ")[0];
String lastName = name.split(" ")[1];
return new Employee(firstName, lastName);
})*/
.collect(Collectors.toList());

System.out.println(listOfEmployeeObjects);
}
}

filter() Operation

filter() operation is used to filter out elements from the streams. suppose you have streams of elements, and you want that certain element which does not match our criteria should be filtered out. and should not be sent ahead for further processing. in such cases, you can use filter() operation. filter operation accepts a Predicate function as an Input.

Syntax :
Stream<T> filter(Predicate<? super T> predicate);

Example :
package org.java4ninja.exploringjava8.streams;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

class Student {
private String name;
private double marksOutOf100;

public Student(String name, double marksOutOf100) {
this.name = name;
this.marksOutOf100 = marksOutOf100;
}

public String getName() { return name; }
public double getMarksOutOf100() { return marksOutOf100; }
}

public class FilterOperationOnStreams {
public static void main(String args[]) {

List<Student> studentList = Arrays.asList(
new Student("Tim", 86),
new Student("Joe", 44),
new Student("Lisa", 91),
new Student("Tom", 52));

Predicate<Student> passingCriteria = student -> student.getMarksOutOf100() > 50;

List<String> listOfStudentWhoPassTheExam = studentList
.stream()
.filter(passingCriteria)
/* more concise way inline predicate function */
//.filter(student -> student.getMarksOutOf100() > 50)
.map(student -> student.getName())
/* more concise way using method reference */
//.map(Student::getName)
.collect(Collectors.toList());

System.out.println(listOfStudentWhoPassTheExam);
}
}

flatMap() Operation

flatMap() is the most confusing operation of streams, Many people gets confuse between map() and flatMap(). It would be easy if you understood them correctly with the correct example. flatMap() operation is used to convert the Streams<Streams<T>> to Streams<T>. basically, if you have a List of elements X, and inside each element, you have another elements Y, in order to create a list of all elements of Y. you can use flatMap(), if you use map() you will end up getting List<List<Y>>.

Syntax :
Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

Example :
package org.java4ninja.exploringjava8.streams;

import java.util.List;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.Data;
import static java.util.Arrays.asList;

/* I have used lombok here in order to write minimal code,You can
always use lombok, or manually create constructor and getter setters*/
@Data @AllArgsConstructor
class Sales {
private String item;
private double price;
}
@Data @AllArgsConstructor
class SalesEmployee {
private String name;
private List<Sales> listOfSales;
}

public class FlatMapOperationOnStreams {
public static void main(String args[]) {
List<SalesEmployee> listOfEmployee = asList(
new SalesEmployee("Joe", asList(
new Sales("Iron", 150),
new Sales("Washing Machine", 1500))),
new SalesEmployee("Honey", asList(
new Sales("Mobile", 1400),
new Sales("TV", 13499))),
new SalesEmployee("Lisa", asList(
new Sales("Bed", 150),
new Sales("Laptop", 12999))),
new SalesEmployee("Hayaat", asList(
new Sales("Pen Drive", 399),
new Sales("Desktop Computer", 8999))));

List<Sales> listOfSales = listOfEmployee
.stream()
.flatMap(employee -> employee.getListOfSales().stream())
.collect(Collectors.toList());

System.out.println(listOfSales);
}
}

distinct() and sorted()

The name itself depicts its usage, distinct() method used to extract out all the distinct elements from the streams. and remove all duplicate elements. distinct does not take any argument as input. 

sorted() method is useful to sort the elements in the streams. it sorts the element in its natural order. It expects that the class should be comparable. otherwise, you can pass a Comparator object to the sorted() method.

Syntax :

Stream<T> distinct();
Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator); 

Example :

package org.java4ninja.exploringjava8.streams;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class DistinctAndSortedOnStreams {
public static void main(String args[]) {

List<Integer> listOfIntegers = Arrays.asList(1, 2, 5, 33, 22, 2,
33, 90, 11, 15, 19, 8, 90, 155, 65, 22);

List<Integer> listOfDistinctAndSortedIntegers = listOfIntegers
.stream()
.distinct()
.sorted()
.collect(Collectors.toList());
System.out.println(listOfDistinctAndSortedIntegers);

List<Integer> listOfDistinctAndSortedInReverseOrderIntegers = listOfIntegers
.stream()
.distinct()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
System.out.println(listOfDistinctAndSortedInReverseOrderIntegers);
}
}

peek() limit() and skip()

peek() operation is more of debugging method in the streams, it accepts a consumer function and generally, we use it for printing things out so that on each step of streams you will come to know which elements are going to pass to the next intermediate operation

limit() operation is used to limit the number of the element which can be pass through the streams. it accepts a Long integer, which used to denote the number of the element should be pass to the next intermediate operations

skip() operation again is used to skip first n elements from the streams. it accepts Long integer which is used to skip the first n elements from the beginning of the streams

Syntax :
Stream<T> peek(Consumer<? super T> action);
Stream<T> limit(long maxSize);
Stream<T> skip(long n);


Example :
package org.java4ninja.exploringjava8.streams;

import java.util.Arrays;
import java.util.stream.Collectors;

public class PeekLimitAndSkipOperation {
public static void main(String args[]) {
Arrays
.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.stream()
// skip first 2 element
.skip(2)
// limit the result for next 5 elements only
.limit(5)
// do a peek a boo on the current elements of streams
.peek((element) -> System.out.println(element))
.peek(System.out::println)
.collect(Collectors.toList());
}
}


I hope you learned all the operations we have discussed in this blog, Let me know your comment, suggestion for this blog. it would be helpful for me to improve myself and my blogs. 

Till then, 
Thank You 
Good-Bye
Happy Coding


Friday, March 12, 2021

Exploring Java 8 : Introduction to Streams API


Hello there techie ninjas, I hope you are doing good. Today we would be learning one of the most amazing features released in Java 8. it provided a lot of value for parallel processing of collections and writing code in functional ways. I would say this is one of the most important chapters of the Java 8 Series so I would be creating this blog in such a fashion that every one of us would understand this functionality.


Before we start, let's discuss what is Steam in general?

I would say stream is something which is in motion. or something is flowing in unidirectional. It could be Air, Gas or Water. You all must have seen a stream of water, it is a continuous flow of water. The same is applicate to Data also, if there is a data in motion we call it a data stream. Innovator of Java 8, saw grate potential in this concept. Till java 8, Most of us were using the collection for storing the Data. But in most of the cases, this stored data will eventually needed to flow between various components of software. There was a lot of common patterns around the collection processing. Innovators of java 8, analyse those and created a Streaming API framework, where now one could able to declare a flowing data in programming, process the streams, and At the end collect and convert it back to stationary data.


With above diagram, I hope you can conceptually able to visualise streams in java. the left  hand side denote the stationary data stored on memory, like your collections - list, map, sets and one on the right hand side are nothing but the java streams. 


Let's see one example to know how you can get a streams in java

package org.java4ninja.exploringjava8.streams;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class HelloStreams {
public static void main(String args[]) {
// Stationary Data
List<String> listOfString = Arrays.asList("Apple",
"Banana",
"Orange",
"Mango",
"Pineapple",
"Grapes");

// Stream made out of Stationary data
Stream<String> stream = listOfString.stream();

// Streams of integer from 1 to 100
IntStream intStreams = IntStream.rangeClosed(1, 100);

// Streams of different languages
Stream<String> someRandomStreams = Stream.of("java", "node", "scala", "bash", "python");
}
}

Different Stages of Streams

Each and every streams has to pass through different stages of operation given below. We have categorised those in 3 different stages

Initialisation Phase -> Intermediate Operations -> Terminal Operation

  • Initilisation phase is nothing but creating streams from any collection, any source of data or just starting with range of intergers from 1 to N. In order to use streaming API, you will need the Stream. We will see different ways of initilising streams in next blog.
  • Intermediate Operations are the operations performed on the flowing data. The streams on which this data flow, we call it as a pipeline. We can apply different intermediate operation on this pipeline, such as filtering elements, converting elements, re-arranging them, skipping element, limiting elements etc.
  • We would be having a separate blog on intermediate operation. Basic intention behind the intermediate operation is to mold the source of data to the another useful format.
  • We can chain these intermediate operation in order to archive desired output.
  • Once we have setup the pipeline, to process data, at the end you need to collect the data in the format you want to project. it can be storing data back in another collection, performing reduce operation, find out cout, checking if any element  exist in streams.
  • Terminal operation, will be end point for stream journey. Stream would be closed and data would be stored back in stationary format. Data will stop flowing on calling terminal operation.

lets take a simple example to understand these different stages, although we would be exploring each of these stages in lot of grater details in next blogs.


package org.java4ninja.exploringjava8.streams;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class HelloStreams {
public static void main(String args[]) {
// Stationary Data
List<String> listOfString = Arrays.asList("Apple", "Banana", "Cat",
"Dog", "Elephant", "Fish", "Grapes", "Hat", "Ice", "Jacket",
"Kite", "Lemon", "Mango", "Newspaper", "Orange", "Parrot",
"Queen", "Rat", "Sun", "Tv", "Umbrella", "Van", "Watch",
"Xmas", "Zebra");

// Initialisation stage
Stream<String> streamsOfString = listOfString.stream();

// intermediate stages
Stream<String> intermediateStringStream = streamsOfString
// intermediate stage of filtering elements
.filter(s -> s.length() > 3)
// intermediate stage of convert each element to upper case
.map(s -> s.toUpperCase())
// intermediate stage of re-ordering elements
.sorted(String::compareTo);

// Terminating streams and collecting all the elements from the stream to list collection
List<String> finalListOfString = intermediateStringStream
.collect(Collectors.toList());

System.out.println(finalListOfString);
}
}

I hope you have got basic idea behind the Streaming API introduced in the java 8. We would be going to talk alot about the initilisation, intermediate stages and terminal stages in upcoming blogs. 

Till then Happy Coding, See you in the next blog. 





















Wednesday, March 10, 2021

Exploring Java 8 : Java Method Reference & Constructor Reference


Hello there techie ninjas, I hope you are doing good. Welcome to Java4Ninja and another blog on Method Reference & Constructor Reference in the Exploring Java 8 Series. Let's get started with the content then.


What is the Method Reference in Java 8?

Method Reference is another way of writing concise lambda of one line, in case your lambda is just calling a function on an object, or a static function on class. let's take the example of the below lambda.

import java.util.function.Consumer;

public class Example {

public void printStringInUpperCase(String str) {
System.out.println(str.toUpperCase());
}

public static void main(String args[]) {
Example example = new Example();
Consumer<String> uppercaseConverterAndPrinter =
(str) -> example.printStringInUpperCase(str);
uppercaseConverterAndPrinter.accept("hello world !");
}
}


In the above code block, the line bold can be written more concisely like below,

Consumer<String> uppercaseConverterAndPrinter =
example::printStringInUpperCase;

This bold highlighted portion is called a method reference. Syntax of method reference is 

objeOfClass::methodWhichCanSatisfyInterfaceContract;
className::staticMethodWhichCanSatisfyInterface;

So In the above example, we have used the Consumer interface, And you might aware from the learning of the previous Blog,  Exploring Java 8: Functional Interface that the consumer interface accepts a parameter of type T and won't return anything. Here in the above example, it satisfies the contract, then function for which we have created a method reference "printStringInUpperCase", it accepts a parameter of type String and does not return anything.

Some more example around the Method Reference & Static Method Reference

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class ConsumerMethodReferenceExample {

public static void stringConsumerStaticMethod(String str) {
System.out.println(str);
}

public void stringConsumerInstanceMethod(String str) {
System.out.println(str);
}

public static void main(String[] args) {

ConsumerMethodReferenceExample instance = new ConsumerMethodReferenceExample();
Consumer<String> stringConsumerLambda = (str) -> ConsumerMethodReferenceExample.stringConsumerStaticMethod(str);
Consumer<String> stringConsumerMethodReference = ConsumerMethodReferenceExample::stringConsumerStaticMethod;
Consumer<String> stringConsumerMethodReferenceWithObject = instance::stringConsumerInstanceMethod;
Consumer<String> stringConsumerMethodReferenceWithCleanerCode = System.out::println;

stringConsumerLambda.accept("ABC");
stringConsumerMethodReference.accept("ABC");
stringConsumerMethodReferenceWithObject.accept("ABC");
stringConsumerMethodReferenceWithCleanerCode.accept("ABC");

List<String> listOfString = Arrays.asList("Apple", "Banana", "Cat", "Dog");
System.out.println("Lambda Way");
listOfString.forEach((str) -> ConsumerMethodReferenceExample.stringConsumerStaticMethod(str));

System.out.println("Method Reference Way");
listOfString.forEach(ConsumerMethodReferenceExample::stringConsumerStaticMethod);
listOfString.forEach(instance::stringConsumerInstanceMethod);

System.out.println("Method Reference Way more cleaner");
listOfString.forEach(System.out::println);
}
}

In the example we have have seen method reference for static and non static function for consumer functional interfaces, Lets have a look at method reference for other type of functional interfaces.
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public class MethodReferenceWithFunctionalInterfaces {
public static void main(String args[]) {
MethodReferenceWithFunctionalInterfaces object = new MethodReferenceWithFunctionalInterfaces();

Consumer<String> someConsumer = object::consumerKindOfMethod;
someConsumer.accept("xyz");

Supplier<Double> someSupplier = object::supplierKindOfMethod;
System.out.println(someSupplier.get());

Predicate<Integer> somePredicate = object::isEvenNumber;
System.out.println(somePredicate.test(126) ? "Even" : "Odd");

Function<List<String>, String> concatString = object::join;
System.out.println(concatString.apply(Arrays.asList("I", "Am", "Java", "Ninja")));
}

// consumer sort of functional interfaces
public void consumerKindOfMethod(String str) {
System.out.println(str);
}

// supplier sort of functional interface
public Double supplierKindOfMethod() {
return Math.random();
}

// you can use predicate interfaces for this
public boolean isEvenNumber(Integer number) {
return number % 2 == 0;
}

//you cabn function functional interface for this
public String join(List<String> list) {
return list.stream().collect(Collectors.joining(" "));
}
}

I hope you have learned the method reference in java 8. In short it is just consice ways of implementation of functional interfaces. Lambda would be little longer way of writing it. but with method reference it is more consice, more redable and more short.

Let's Start with Constructor Reference Now

Constructor reference is also similar to the method reference we have seen earlier. but there is one difference constructor reference will always be of type Function Functional interface. it would accept parameter to pass in the constructor and will always return the object of a class. Java has Functional and BiFunction functional interface available in java.lang.function package. Function for single parameter input, BiFunction is for two input parameter for a constructor.

Lets look at below example which shows how you can code for Constructor reference.

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

class Things {
private String name;

public Things(String name) {
this.name = name;
}
}

public class ConstructorReferenceExample {
public static void main(String args[]) {
Function<String, Things> function = Things::new;
Things apple = function.apply("Apple");

/* Some real industry example about the constructor reference*/
List<String> thingsString = Arrays.asList("Apple", "Ball", "Cat", "Dog", "Egg");

List<Things> listOfThings = thingsString
.stream()
.map(Things::new) // accept a string and return object of class Things
.collect(Collectors.toList());
}
}

I Hope you have understood the conecpt behind method reference and constructor reference introudced in java 8. Basic intention behind the method reference is make your connsie, redable and allows you to pass function as a parameter which can be invoke later point in time based on your logic. it will allow you to build a code in call back fashion, where you will decalre your function, but it would be invoke far below in the call stack.


Thats all for this blog ninjas. Let me know if you have any question, feedback, suggestion. I will always try to improve my blogs and will be happy to help you.

Till then Good Bye, Happy Coding !!!



Tuesday, March 9, 2021

Exploring Java 8 : Functional Interface


Welcome to Java 4 Ninja, Today in this blog we would be exploring Functional interfaces that were introduced in Java 8. Although we talked about functional interfaces a little bit, this blog would be completely hands-on on functional interfaces. We would be covering the Why, What, and How for the functional interfaces. If you haven't check out my previous blog "Exploring Java 8: Lambda in java" please do checkout. That would set the stage for this blog. Let's get started then.


What is Functional Interface?

As we have seen in the previous blog, Functional Interface in Java 8 is an Interface in java with only a single abstract method. All Functional Interfaces are annotated with @FunctionalInterface annotation. 


Why there is a need for a Functional Interface or An Interface with only one abstract method?

With Java 8, Java is set the stage for supporting the functional programming style paradigm. Functional Programming says that you should treat the function as a first-class citizen,  Object-oriented programming emphasis mutating the state of objects, while Functional programming says that you should never mutate the state of the object, instead your function should create immutable objects. and name of the function should clearly specify the final state of objects. For each such function, we can have a functional interface. Such a functional interface can be implemented very well using lambda and it would be easily readable and clean code. Although you would rarely need to create one since java 8 has a whole bunch of functional interfaces for n number of operations. You might see this information not so clear, but when you start programming in a functional style, you will come to know the advantage of it.


How to Declare your own functional interface?

It would be very easy, you can create a normal interface in java. To make your interface a functional interface, make sure it has only a single abstract un-implemented method. That all it required. Annotating your interface with @FunctionalInterface will tell the compiler that this interface would be used as a functional one, don't allow anyone in the future to add more methods. if so give compile error about that. However it is optional, but a good safety net to work in a collaborative team.

 Let's have look at below basic example of declaring a functional interface

@FunctionalInterface
interface MyInterface {
public void doSomething();
}


Basic Functional Interfaces in Java 8

Java 8 comes with a bunch of functional interfaces which are getting used in many of the Java 8 features like streams. There are some common functional interfaces that you will definitely face while doing functional programming. We would be exploring those. Once you are familiar with those, I am pretty sure that you will learn which one to use in which scenario. So let's get started with it.

Consumer Functional Interface

As the name tell this functional interface act as a consumer. Let's first understand what do you mean by a consumer. A consumer is something, which accepts input and processes it.  It won't give feedback to the caller. That means, it did not return anything. So while programming, if you come across such a scenario, you can use the consumer interface. A typical example would be printing somethings, write something to the database, send something to another client.

This is how the functional Interface look like for the Consumer

@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Below is an example of a consumer example that consumes string and prints it on the console.

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class ConsumerExample {
public static void main(String args[]) {
List<String> listOfStrings = Arrays.asList("Apple", "Ball", "Cat", "Dog", "Egg", "Fish");

/* Easy way for beginners */
Consumer<String> printConsumer = (input) -> System.out.println(input);
listOfStrings.forEach(printConsumer);

/* Cleaner and shorter way */
listOfStrings.forEach((input) -> System.out.println(input));
}
}

Predicate Functional Interface

As the name suggests, this interface has a method, named test. it will act as a predicate for the input. You can pass input to it. function body will have a code that can determine whether the pass input is valid for some condition and it will return a boolean. Let's have a look at the predicate functional interface available in java 8.

@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}

let's have a look at the below example, which demonstrates the usage of the predicate interface. In the below example, we have used the Streams API, which was introduced in java8. You might not be familiar with that, but as of now, you can think it is like an iterator on the lists. We would be going to learn about Streams API in-depth going ahead in this blog.

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class PredicateExample {
public static void main(String args[]) {
List<String> listOfStrings = Arrays.asList("Apple", "Ball", "Cat",
"Dog", "Egg", "Fish", "Ground",
"Horse", "Ice-Cream", "Juice",
"Kite", "Lemon", "Mango", "Nest",
"Orange", "Pears", "Queen", "Rat",
"Sun", "Tv", "Umbrella", "Volvo", "Watch", "Xray", "Zebra");

// Predicate which accept string, check its length and if it is 3 or less
// then return true otherwise it will return false
Predicate<String> predicate = (input) -> input.length() <= 3;

List<String> listWithOnly4letter = listOfStrings
// consider this as elements are iterating one by one
.stream()
// Applying our predicate, filter function which only
// send those value to next level for which predicate return true
.filter(predicate)
// collect all element who pass ed filter test
.collect(Collectors.toList());

System.out.println(listWithOnly4letter);
}
}


Supplier Functional Interface

As the name suggests, the Supplier functional interface deals only with supplying values without any input. this is how the supplier interface looks like.

@FunctionalInterface
public interface Supplier<T> {
T get();
}

Let's have a look at the below example, where we have created a double supplier of random values. one can simply invoke the get method of it and they will get a random value.

import java.util.function.Supplier;

public class SupplierExample {
public static void main(String args[]) {
Supplier<Double> doubleSupplier = () -> Math.random();
System.out.println(doubleSupplier.get());
}
}


Function Functional Interface

A function interface acts as a converter sort of thing. it accepts one parameter of type X and can return the value of type X or Y. whenever you have a use case of converting or transforming something into another form. you can use this interface.  below is the signature of the functional interface

@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}

Let's have a look at the below example,  Again this example would be related to streams. think this example similar to the predicate example.


import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class FunctionalInterfaceExample {
public static void main(String args[]) {

List<String> listOfStrings = Arrays.asList("one", "two", "three");

Function<String, String> transformer = (str) -> str.toUpperCase();

String normalString = "abc";
String upperCaseString = transformer.apply(normalString);
System.out.println(upperCaseString);


List<String> upperCaseStringList = listOfStrings
.stream()
.map(transformer)
.collect(Collectors.toList());

System.out.println(upperCaseStringList);
}
}


There are lots of other functional interfaces available in java 8. explore other functional Interfaces added as part of Java 8 in the package "java.util.function"


That's all for this tutorial friends. stay tune on Java4Ninja. See you in the next Blog.