Lambdas
it is an anonymous function. without return type and without modifiers.
the objective of a lambda expression is
1)to bring functional programming benefits in java.
2) write more readable, maintainable & concise code
3) to use API very easily and effectively
4) enable parallel processing
eg1:
public void m1()
{
System.out.println("Hello");
}
can be written as
()-> System.out.println("Hello");
eg2:
public void add(int a,int b)
{
System.out.println(a+b);
}
can be written as
(int a, int b)-> System.out.println(a+b);
also
(a,b)-> System.out.println(a+b);
eg3:
public int square(int n)
{
return n*n;
}
can be written as
(int n)->{return n*n;}
also
(n)->return n*n;
also
n->n*n;
eg4:
public int m1(String s)
{
return s.length();
}
can be written as
s->s.length();
Functional interfaces
Any interface with only one abstract method is known as a functional interface.
case 1: if a parent interface is functional interface and child interface is marker
@FunctionalInterface
interface P
{
public void m1();
}
@FunctionalInterface
interface C extends P
{
}
the scenario is valid
case 2:
@FunctionalInterface
interface P
{
public void m1();
}
@FunctionalInterface
interface C extends P
{
public void m1();
}
valid scenario
case 3:
@FunctionalInterface
interface P
{
public void m1();
}
@FunctionalInterface
interface C extends P
{
public void m2();
}
Error: java: Unexpected @FunctionalInterface annotation
LambdaFeatures.C is not a functional interface
multiple non-overriding abstract methods found in interface LambdaFeatures.C
Invoking Lambda Expression By using Functional Interface example-1
@FunctionalInterface
interface Intref{
public void m1();
}
class A implements Intref{
@Override
public void m1() {
System.out.println("normal implementation");
}
}
public class FIPract1 {
public static void main(String[] args) {
Intref i1=new A();
i1.m1();
Intref i2= ()->System.out.println("implemented Lambda");
i2.m1();
}
}
O/P:
normal implementation
implemented Lambda
Invoking Lambda Expression By using Functional Interface example-2
public class FIPract2 {
public static void main(String[] args) {
Interf i1=new Demo();
i1.add(2,3);
Interf i2= (a,b) -> System.out.println("sum is "+(a+b));
i2.add(3,4);
}
}
interface Interf
{
public void add(int a,int b);
}
class Demo implements Interf{
@Override
public void add(int a, int b) {
System.out.println("sum is "+(a+b));
}
}
O/P:
sum is 5
sum is 7
Invoking Lambda Expression By using Functional Interface example-2
public class FIPract2 {
public static void main(String[] args) {
Interf i1=new Demo();
System.out.println("length is "+i1.getLength("Hello"));
Interf i2=s -> s.length();
System.out.println(i2.getLength("haiii"));
Interf i3=(String::length);
System.out.println(i3.getLength("hai"));
}
}
interface Interf
{
public int getLength(String s);
}
class Demo implements Interf{
@Override
public int getLength(String s) {
return s.length();
}
}
O/P:
length is 5
5
3
public static void main(String[] args) {
List<Integer> l=new ArrayList<Integer>();
l.add(21);
l.add(5);
l.add(68);
l.add(45);
System.out.println("before sorting"+l);
Collections.sort(l,(a,b) -> (a>b)?-1:(a<b)?1:0);
System.out.println("after sorting"+l);
Set<Integer> set=new TreeSet<Integer>((a,b) -> (a>b)?-1:(a<b)?1:0);
set.add(35);
set.add(22);
set.add(12);
set.add(45);
System.out.println("Set is"+set);
Map<Integer,String> map=new TreeMap<Integer,String>((a,b) -> (a>b)?-1:(a<b)?1:0);
map.put(6,"abc");
map.put(600,"abc");
map.put(340,"abc");
map.put(650,"abc");
System.out.println("map is "+map);
}
O/P:
before sorting[21, 5, 68, 45]
after sorting[68, 45, 21, 5]
Set is[45, 35, 22, 12]
map is {650=abc, 600=abc, 340=abc, 6=abc}
the method level local variable used in Lambda expression must be final or effectively final.
public class FIPract4 {
int x=10;
public void m2(){
int y=20;
Inte i=()->{
System.out.println(x);
System.out.println(y);
x=999;
y=888; //the local variables inside lambda are implicitly final
};
i.m1();
}
public static void main(String[] args) {
FIPract4 p=new FIPract4();
p.m2();
}
}
interface Inte {
public void m1();
}
OUTPUT:
Error:(12, 28) java: local variables referenced from a lambda expression must be final or effectively final
Default methods inside the interface
eg:
public class DefaultInter implements DefInt{
public void m1(){
System.out.println("own implementation");
}
public static void main(String[] args) {
DefaultInter d=new DefaultInter();
d.m1();
}
}
interface DefInt
{
default void m1(){
System.out.println("default");
}
}
Output: own implementation
default method with same name in parralel class
public class DefaultInter2 implements Left,Right {
public static void main(String[] args) {
DefaultInter2 d=new DefaultInter2();
}
}
interface Left{
default void m1(){
System.out.println("left interface");
}
}
interface Right{
default void m1(){
System.out.println("right interface");
}
}
O/P: Error:java: class LambdaFeatures.DefaultInter2 inherits unrelated defaults for m1() from types LambdaFeatures.Left and LambdaFeatures.Right
solution is to mandatorily implement methods
public class DefaultInter2 implements Left,Right {
public static void main(String[] args) {
DefaultInter2 d=new DefaultInter2();
d.m1();
}
@Override
public void m1() {
System.out.println("own implementation");
Left.super.m1();
Right.super.m1();
}
}
interface Left{
default void m1(){
System.out.println("left interface");
}
}
interface Right{
default void m1(){
System.out.println("right interface");
}
O/P: own implementation
left interface
right interface
Method reference & constructor reference by :: OPERATOR
for static method class name would be enough for reference but when it comes to non-static methods there needs object reference for the same. the only requirement is the same argument type
public class MethodReference {
public static void main(String[] args) {
MethodReference m=new MethodReference();
Runnable r= m::m1;
Runnable r2=MethodReference::m2;
Thread t=new Thread(r);
Thread t1=new Thread(r2);
t.start();
t1.start();
for (int i=0;i<10;i++){
System.out.println("main thread");
}
}
public void m1(){
for (int i=0;i<10;i++){
System.out.println("child thread");
}
}
public static void m2(){
for (int i=0;i<10;i++){
System.out.println("child thread 2");
}
}
}
Constructor reference
public class ConstReference {
public static void main(String[] args) {
Int4 i=Sample::new;
i.get();
}
}
class Sample{
Sample(){
System.out.println("created sample object");
}
}
interface Int4{
Sample get();
}
O/P:created sample object
Streams
Streams is useful when we want to process objects from Collection .
public class StreamPract1 {
public static void main(String[] args) {
ArrayList<Integer> l=new ArrayList<Integer>();
l.add(0);
l.add(13);
l.add(20);
l.add(25);
System.out.println(l);
//without stream
for (Integer i1: l){
if (i1%2==0) System.out.println(i1);
}
//with stream
List<Integer> l1= l.stream().filter(i->i%2==0).collect(Collectors.toList());
System.out.println(l1);
//without stream
for (Integer i1: l) System.out.println(i1*2);
//with stream
System.out.println(l.stream().map(i->i*2).collect(Collectors.toList()));
}
}
O/P:
[0, 13, 20, 25]
0
20
[0, 20]
0
26
40
50
[0, 26, 40, 50]
Processing by collect() method
This method collects the element from the Stream and adds it to the specified collection.
eg:
map(i->i*2).collect(Collectors.toList()));
Processing by count() method
the method returns the number of elements present in the stream.
eg:
public static void main(String[] args) {
ArrayList<Integer> l=new ArrayList<Integer>();
l.add(0);
l.add(13);
l.add(20);
l.add(25);
l.add(33);
long count=l.stream().filter(i->i%2!=0).count();
System.out.println("odd number is"+count);
}
O/P: odd numbers is 3
Processing by sorted() method
we can use the sorted() method to sort elements inside Stream. we can sort either based on default natural sorting order or customized sorting order.
sorted() or sorted(Comparator c)
public class StreamPract2 {
public static void main(String[] args) {
ArrayList<Integer> l=new ArrayList<Integer>();
l.add(20);
l.add(33);
l.add(25);
l.add(0);
l.add(13);
System.out.println(l.stream().sorted().collect(Collectors.toList()));
System.out.println(l.stream().sorted((a,b)->-a.compareTo(b)).collect(Collectors.toList()));
}
}
O/P:
[0, 13, 20, 25, 33]
[33, 25, 20, 13, 0]
Processing by min() & max() method
public static void main(String[] args) {
ArrayList<Integer> l=new ArrayList<Integer>();
l.add(20);
l.add(33);
l.add(25);
l.add(13);
l.add(4);
Integer min=l.stream().min((a,b)->a.compareTo(b)).get();
Integer max=l.stream().max((a,b)->a.compareTo(b)).get();
System.out.println("minimum is "+min);
System.out.println("maximum is "+max);
}
O/P:
minimum is 4
maximum is 33
Processing using forEach() method
this method won't return anything, it just takes Lambda expression as argument and apply that Lambda expression for each element present in Stream.
ArrayList<Integer> l=new ArrayList<Integer>();
l.add(20);
l.add(33);
l.add(25);
l.add(13);
l.add(4);
l.stream().forEach(System.out::println);
O/P:
20
33
25
13
4
Processing using toArray() method
Integer[] array=l.stream().toArray(Integer[]::new);
Stream.of()
DATE-TIME API (Joda time API)
public class DaTimePract {
public static void main(String[] args) {
LocalDate date=LocalDate.now();
//System.out.println(date);
int dd=date.getDayOfMonth();
int mm=date.getMonthValue();
int yy=date.getYear();
System.out.printf("%d-%d-%d\n",dd,mm,yy);
LocalTime time=LocalTime.now();
//System.out.println(time);
int h=time.getHour();
int m=time.getMinute();
int s=time.getSecond();
int n=time.getNano();
System.out.printf("%d;%d;%d;%d\n",h,m,s,n);
LocalDateTime dt=LocalDateTime.of(1996,10,15,16,21);
System.out.println(dt);
LocalDate bday=LocalDate.of(1996,10,15);
System.out.println(dt.plusMonths(3));
Period p=Period.between(bday,date);
System.out.println("age is "+p);
int ye=2100;
Year year=Year.of(ye);
if (year.isLeap()){
System.out.println("leap year "+year);
}
else System.out.println("not leap "+year);
ZoneId z=ZoneId.systemDefault();
System.out.println(z);
ZoneId z1=ZoneId.of("America/Los_Angeles");
ZonedDateTime zdt=ZonedDateTime.now(z1);
System.out.println(zdt);
}