Oop Unit 3 Part1
Oop Unit 3 Part1
Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. It
is a new feature in Java, which helps to achieve functional programming approach.
Example 1
1. @FunctionalInterface
2. interface sayable{
3. void say(String msg);
4. }
5. public class FunctionalInterfaceExample implements sayable{
6. public void say(String msg){
7. System.out.println(msg);
8. }
9. public static void main(String[] args) {
10. FunctionalInterfaceExample fie = new FunctionalInterfaceExample();
11. fie.say("Hello there");
12. }
13. }
Test it Now
Output:
Hello there
A functional interface can have methods of object class. See in the following example.
Example 2
1.
2. @FunctionalInterface
3. interface sayable{
4. void say(String msg); // abstract method
5. // It can contain any number of Object class methods.
6. int hashCode();
7. String toString();
8. boolean equals(Object obj);
9. }
10. public class FunctionalInterfaceExample2 implements sayable{
11. public void say(String msg){
12. System.out.println(msg);
13. }
14. public static void main(String[] args) {
15. FunctionalInterfaceExample2 fie = new FunctionalInterfaceExample2();
16. fie.say("Hello there");
17. }
18. }
Output:
Hello there
A functional interface can extends another interface only when it does not have any abstract
method.
1. interface sayable{
2. void say(String msg); // abstract method
3. }
4. @FunctionalInterface
5. interface Doable extends sayable{
6. // Invalid '@FunctionalInterface' annotation; Doable is not a functional interface
7. void doIt();
8. }
Output:
compile-time error
Example 3
1. interface Doable{
2. default void doIt(){
3. System.out.println("Do it now");
4. }
5. }
6. @FunctionalInterface
7. interface Sayable extends Doable{
8. void say(String msg); // abstract method
9. }
10. public class FunctionalInterfaceExample3 implements Sayable{
11. public void say(String msg){
12. System.out.println(msg);
13. }
14. public static void main(String[] args) {
15. FunctionalInterfaceExample3 fie = new FunctionalInterfaceExample3();
16. fie.say("Hello there");
17. fie.doIt();
18. }
19. }
Output:
Hello there
Do it now
You can also define your own custom functional interface. Following is the list of functional
interface which are placed in java.util.function package.
Interface Description
BinaryOperator<T> It represents an operation upon two operands of the same data type.
It returns a result of the same type as the operands.
IntBinaryOperator It represents an operation upon two int type operands and returns
an int type result.
LongBinaryOperator It represents an operation upon two long type operands and returns
a long type result.
In Java, Lambda expressions basically express instances of functional interfaces
(An interface with a single abstract method is called a functional interface).
Lambda Expressions in Java are the same as lambda functions which are the short
block of code that accepts input as parameters and returns a resultant value.
Lambda Expressions are recently included in Java SE 8.
Functionalities of Lambda Expression in Java
Lambda Expressions implement the only abstract function and therefore
implement functional interfaces lambda expressions are added in Java 8 and
provide the below functionalities.
Enable to treat functionality as a method argument, or code as data.
A function that can be created without belonging to any class.
A lambda expression can be passed around as if it was an object and executed
on demand.
Java Lambda Expression Example
Java
// Java program to demonstrate lambda expressions
// to implement a user defined functional interface.
Output
10
Output
1
2
3
4
2
4
Note: that lambda expressions can only be used to implement functional interfaces.
In the above example also, the lambda expression implements Consumer Functional
Interface.
3. Lambda Expression with Multiple parameters
(p1, p2) -> System.out.println("Multiple parameters: " + p1 + ", " + p2);
A Java program to demonstrate the working of a lambda expression with two
arguments.
Java
// Java program to demonstrate working of lambda expressions
public class Test {
// operation is implemented using lambda expressions
interface FuncInter1 {
int operation(int a, int b);
}
Output
Addition is 9
Multiplication is 18
Hello Geek
Note: Lambda expressions are just like functions and they accept parameters just
like functions.
Conclusion
Some Important points intake from this article is mentioned below:
The body of a lambda expression can contain zero, one, or more statements.
When there is a single statement curly brackets are not mandatory and the
return type of the anonymous function is the same as that of the body
expression.
When there is more than one statement, then these must be enclosed in curly
brackets (a code block) and the return type of the anonymous function is the
same as the type of the value returned within the code block, or void if nothing
is returned.
Java provides a new feature called method reference in Java 8. Method reference is used to
refer method of functional interface. It is compact and easy form of lambda expression. Each
time when you are using lambda expression to just referring a method, you can replace your
lambda expression with method reference. In this tutorial, we are explaining method
reference concept in detail.
Syntax
1. ContainingClass::staticMethodName
Example 1
In the following example, we have defined a functional interface and referring a static method
to it's functional method say().
1. interface Sayable{
2. void say();
3. }
4. public class MethodReference {
5. public static void saySomething(){
6. System.out.println("Hello, this is static method.");
7. }
8. public static void main(String[] args) {
9. // Referring static method
10. Sayable sayable = MethodReference::saySomething;
11. // Calling interface method
12. sayable.say();
13. }
14. }
Test it Now
Output:
Example 2
In the following example, we are using predefined functional interface Runnable to refer static
method.
Thread is running...
Example 3
You can also use predefined functional interface to refer methods. In the following example,
we are using BiFunction interface and using it's apply() method.
1. import java.util.function.BiFunction;
2. class Arithmetic{
3. public static int add(int a, int b){
4. return a+b;
5. }
6. }
7. public class MethodReference3 {
8. public static void main(String[] args) {
9. BiFunction<Integer, Integer, Integer>adder = Arithmetic::add;
10. int result = adder.apply(10, 20);
11. System.out.println(result);
12. }
13. }
Test it Now
Output:
30
Example 4
You can also override static methods by referring methods. In the following example, we have
defined and overloaded three add methods.
1. import java.util.function.BiFunction;
2. class Arithmetic{
3. public static int add(int a, int b){
4. return a+b;
5. }
6. public static float add(int a, float b){
7. return a+b;
8. }
9. public static float add(float a, float b){
10. return a+b;
11. }
12. }
13. public class MethodReference4 {
14. public static void main(String[] args) {
15. BiFunction<Integer, Integer, Integer>adder1 = Arithmetic::add;
16. BiFunction<Integer, Float, Float>adder2 = Arithmetic::add;
17. BiFunction<Float, Float, Float>adder3 = Arithmetic::add;
18. int result1 = adder1.apply(10, 20);
19. float result2 = adder2.apply(10, 20.0f);
20. float result3 = adder3.apply(10.0f, 20.0f);
21. System.out.println(result1);
22. System.out.println(result2);
23. System.out.println(result3);
24. }
25. }
Test it Now
Output:
30
30.0
30.0
Syntax
1. containingObject::instanceMethodName
Example 1
In the following example, we are referring non-static methods. You can refer methods by class
object and anonymous object.
1. interface Sayable{
2. void say();
3. }
4. public class InstanceMethodReference {
5. public void saySomething(){
6. System.out.println("Hello, this is non-static method.");
7. }
8. public static void main(String[] args) {
9. InstanceMethodReference methodReference = new InstanceMethodReference(); // Creating obj
ect
10. // Referring non-static method using reference
11. Sayable sayable = methodReference::saySomething;
12. // Calling interface method
13. sayable.say();
14. // Referring non-static method using anonymous object
15. Sayable sayable2 = new InstanceMethodReference()::saySomething; // You can use anonymo
us object also
16. // Calling interface method
17. sayable2.say();
18. }
19. }
Test it Now
Output:
Example 2
In the following example, we are referring instance (non-static) method. Runnable interface
contains only one abstract method. So, we can use it as functional interface.
Output:
Example 3
In the following example, we are using BiFunction interface. It is a predefined interface and
contains a functional method apply(). Here, we are referring add method to apply method.
1. import java.util.function.BiFunction;
2. class Arithmetic{
3. public int add(int a, int b){
4. return a+b;
5. }
6. }
7. public class InstanceMethodReference3 {
8. public static void main(String[] args) {
9. BiFunction<Integer, Integer, Integer>adder = new Arithmetic()::add;
10. int result = adder.apply(10, 20);
11. System.out.println(result);
12. }
13. }
Test it Now
Output:
30
3) Reference to a Constructor
You can refer a constructor by using the new keyword. Here, we are referring constructor
with the help of functional interface.
Syntax
1. ClassName::new
Example
1. interface Messageable{
2. Message getMessage(String msg);
3. }
4. class Message{
5. Message(String msg){
6. System.out.print(msg);
7. }
8. }
9. public class ConstructorReference {
10. public static void main(String[] args) {
11. Messageable hello = Message::new;
12. hello.getMessage("Hello");
13. }
14. }
Test it Now
Output:
Hello
Stream In Java
import java.util.*;
import java.util.stream.*;
class Demo {
List<Integer> square
= number.stream()
.map(x -> x * x)
.collect(Collectors.toList());
List<String> result
= names.stream()
.collect(Collectors.toList());
System.out.println(result);
List<String> show
= names.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(show);
List<Integer> numbers
= Arrays.asList(2, 3, 4, 5, 2);
Set<Integer> squareSet
= numbers.stream()
.map(x -> x * x)
.collect(Collectors.toSet());
System.out.println(squareSet);
number.stream()
.map(x -> x * x)
int even
= number.stream()
.filter(x -> x % 2 == 0)
System.out.println(even);
Output
[4, 9, 16, 25]
[Stream]
[Collection, Reflection, Stream]
[16, 4, 9, 25]
4
9
16
25
6
Important Points/Observations of Java Stream
1. A stream consists of a source followed by zero or more intermediate methods
combined together (pipelined) and a terminal method to process the objects
obtained from the source as per the methods described.
2. Stream is used to compute elements as per the pipelined methods without
altering the original value of the object.
// methods in java
interface TestInterface
// abstract method
// default method
System.out.println(a*a);
d.square(4);
d.show();
Output:
16
Default Method Executed
The default methods were introduced to provide backward compatibility so that
existing interfaces can use the lambda expressions without implementing the
methods in the implementation class. Default methods are also known
as defender methods or virtual extension methods.
Static Methods:
The interfaces can have static methods as well which is similar to static method of
classes.
// methods in java
interface TestInterface
{
// abstract method
// static method
System.out.println(a*a);
d.square(4);
TestInterface.show();
}
Output:
16
Static Method Executed
Default Methods and Multiple Inheritance
In case both the implemented interfaces contain default methods with same
method signature, the implementing class should explicitly specify which default
method is to be used or it should override the default method.
interface TestInterface1
// default method
System.out.println("Default TestInterface1");
interface TestInterface2
// Default method
System.out.println("Default TestInterface2");
}
// Implementation class code
TestInterface1.super.show();
TestInterface2.super.show();
d.show();
Output:
Default TestInterface1
Default TestInterface2
Important Points:
1. Interfaces can have default methods with implementation in Java 8 on later.
2. Interfaces can have static methods as well, similar to static methods in classes.
3. Default methods were introduced to provide backward compatibility for old
interfaces so that they can have new methods without affecting existing code.
Static Methods
Static Methods in Interface are those methods, which are defined in the
interface with the keyword static. Unlike other methods in Interface, these static
methods contain the complete definition of the function and since the definition
is complete and the method is static, therefore these methods cannot be
overridden or changed in the implementation class.
Similar to Default Method in Interface, the static method in an interface can be
defined in the interface, but cannot be overridden in Implementation Classes. To
use a static method, Interface name should be instantiated with it, as it is a part
of the Interface only.
Below programs illustrate static methods in interfaces:
Program 1: To demonstrate use of Static method in Interface.
In this program, a simple static method is defined and declared in an interface
which is being called in the main() method of the Implementation Class
InterfaceDemo. Unlike the default method, the static method defines in Interface
hello(), cannot be overridden in implementing the class.
Java
interface NewInterface {
// static method
}
// Implementation Class
NewInterface.hello();
@Override
System.out.println(str);
Output:
Hello, New Static Method Here
Hello, Override Method here
Program 2: To demonstrate Scope of Static method.
In this program, the scope of the static method definition is within the interface
only. If same name method is implemented in the implementation class then that
method becomes a static member of that respective class.
Java
interface PrintDemo {
// Static Method
PrintDemo.hello();
Output:
Called from Interface PrintDemo
Called from Class
Base64 is a binary-to-text encoding scheme that takes raw input bytes and encodes it in a
radix-64 representation, using the characters A-Z, a-z, 0-9, and the symbols +, / and =.
Base64 encoding is used when there is a need to store or transmit binary data over a system
that only supports text data, without losing or corrupting said data.
Java 8 provides a Base64 class in the java.util package which can be used to encode strings
into Base64, and decode Base64 strings into normal strings.
System.out.println(base64String);
// prints: aGVsbG8gd29ybGR+
We can also perform the entire conversion within a single expression, as shown below:
String inputString = "hello world~";
// prints: aGVsbG8gd29ybGR+
System.out.println(decodedString);
System.out.println(decodedString);
We can fetch the URL-safe encoder using Base64.getUrlEncoder(). Then, we can convert our
input string to Base64 using the encodeToString() method:
String inputString = "hello world~";
System.out.println(base64String);
// prints: aGVsbG8gd29ybGR-
Similarly, we can fetch the URL-safe decoder using Base64.getUrlDecoder() method, and we
can convert a Base64-encoded string using the decode() method like so:
String inputString = "aGVsbG8gd29ybGR-";
System.out.println(decodedString);
System.out.println(base64String);
// prints: dGhpcyBpcyBhIHN0cmluZw
Had we not used the withoutPadding() option, we would have got the
string dGhpcyBpcyBhIHN0cmluZw== as the output.
There are no special steps required for decoding the Base64-encoded string without
padding. It can be decoded using the regular Base64 decoder, like so:
String inputString = "dGhpcyBpcyBhIHN0cmluZw";
System.out.println(decodedString);
To convert a string into a MIME-compliant Base64 encoding, we can fetch the MIME-
compliant encoder by using Base64.getMimeEncoder(), and then pass the input string to
the encodeToString() method:
String inputString = "The quick brown fox jumps over the lazy dog. " +
System.out.println(base64String);
The program produces the following output. Since there are 172 characters in the output, it
has been split on to 3 lines.
VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4gSmFja2Rhd3MgbG92
ZSBteSBiaWcgc3BoaW54IG9mIHF1YXJ0ei4gUGFjayBteSBib3ggd2l0aCBmaXZlIGRvemVuIGxp
cXVvciBqdWdzLg==
We can decode a MIME-compliant Base64 string by fetching the MIME-compliant decoder
with Base64.getMimeDecoder():
String inputString =
"VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4gSmFja2Rhd3MgbG92\r\n" +
"ZSBteSBiaWcgc3BoaW54IG9mIHF1YXJ0ei4gUGFjayBteSBib3ggd2l0aCBmaXZlIGRvemVuIGxp\r\n" +
"cXVvciBqdWdzLg==";
System.out.println(decodedString);