Java 8 features
1. Lambda expression
2. Method References
- It is an alternative to Lambda expr
- Also used to access the method of functional interface, instead of writing logic separately using lambda expr we can refer to the methods that already exists
- When signature of interface method matches with static method or instance method or constructor
- Denoted by ::
3 types
1. Reference to static method
2. Reference to instance method
interface MyInterface{
void show();
}
public class Main {
/*public static void add() {
System.out.println("Reference to static method");
}*/
public void sum() {
System.out.println("Reference to instance method");
}
public static void main(String...args) {
MyInterface m1=()->System.out.println("Using Lambda");
m1.show(); //Using Lambda
//MyInterface m2=Main::add;
// m2.show(); //Reference to static method
Main m3=new Main();
MyInterface m4=m3::sum;
m4.show(); //Reference to instance method
}
}
3. Reference to constructor
interface MyInterface{
//Main show();
Main show(String s);
}
public class Main {
Main() {
System.out.println("Reference to default constructor");
}
Main(String s) {
System.out.println("Reference to constructor: "+s);
}
public static void main(String...args) {
// MyInterface m1=Main::new;
// m1.show(); //Reference to default constructor
MyInterface m1=Main::new;
m1.show("Hello"); //Reference to constructor: Hello
}
}
Predefined Functional Interface
- present in java.util.function.* package
1. Consumer interface
void accept(T t);
From JDK1.8 List and Set interface introduced a method called void forEach(Consumer c) - used to iterate elts of List and Set interface individually
2. BiConsumer interface
void accept(T t, U u);
From JDK1.8 Map interface introduced a method called void forEach(BiConsumer c) - used to iterate elts of Map interface individually
3. Function interface
R apply(T t)
4. BiFunction interface
R apply(T t, U u)
5. Predicate interface
boolean test(T t)
6. BiPredicate interface
boolean test(T t, U u)
7. Supplier interface
T get()
8. BooleanSupplier interface
boolean getAsBoolean()
9. UnaryOperator interface extends Function interface
R apply(T t)
10. BinaryOperator interface extends BiFunction interface
R apply(T t, U u)
public class Main {
public static void main(String...args) {
List<String> l1=new ArrayList<>();
l1.add("Ram");
l1.add("Sam");
l1.add("Tam");
l1.add("Jam");
System.out.println(l1); //[Ram,Sam,Tam,Jam]
// l1.forEach((e)->System.out.println(e)); //lambda expr
l1.forEach(System.out::println); //reference to instance method
Map<Integer,String> hm=new HashMap<>();
hm.put(20, "Ram");
hm.put(10, "Sam");
hm.put(30, "Jam");
hm.put(40, "Tam");
System.out.println(hm); //{20=Ram, 40=Tam, 10=Sam, 30=Jam}
hm.forEach((k,v)->System.out.println("Key: "+k+" Value: "+v));
Function<String,Integer> f1=(s)->s.length();
System.out.println(f1.apply("hello")); //5
BiFunction<Integer,Integer,Integer> bf=(x1,y1)->x1+y1;
System.out.println(bf.apply(10,20)); //30
Predicate<String> p=(p1)->p1.startsWith("Foo");
System.out.println(p.test("Foobar")); //true
BiPredicate<Integer,String> bp=(a1,a2)->a1>10 & a2.endsWith("Bar");
System.out.println(bp.test(25, "Foobar")); //true
Supplier<String> su=()->"hello";
System.out.println(su.get()); //hello
BooleanSupplier bp1=()->10>20;
System.out.println(bp1.getAsBoolean()); //false
BiFunction<Integer,String,Boolean> bf1=(x1,y1)->x1>10 & y1.startsWith("Foo");
System.out.println(bf1.apply(20,"Foobar")); //true
BinaryOperator<String> bo=(s1,s2)->s1.concat(s2);
System.out.println(bo.apply("Hello", "world"));
}
}
Streams API
- used to process collection of objects with less number of coding
- fetch collection of objects from some source(ie) List or Set or Array and process them sequentially
- Collection framework also stores collection of objects and we can manipulate and process the object, but with streams api we can only process the collection of object and we cant manipulate it
- present in java.util.streams.* package
- 2 types - finite(fixed value) and infinite(unlimited value) streams
- 2 types of operation
1. Intermediate operation - return stream itself - optional - we can chain multiple intermediate operation at the same time
- filter(), map(), flatMap(), sorted(), peek(), skip(), limit(), distinct(), dropWhile(), takeWhile()
2. Terminal operation - It will traverse into newly generated streams and returns a single value - mandatory - we cant chain multiple terminal operation
- toArray(), forEach(), count(), min(), max(), reduce(), collect(), anyMatch(), allMatch(), noneMatch(), findFirst()
3 steps
Creation of stream - Intermediate operation - Terminal operation
- If we perform terminal operation then that stream is completely closed, so when we perform any other operation on closed stream then we get IllegalStateException
1. Creation of Stream(Finite stream) - 2 ways
1. stream() - used to create a stream from some source like List or Set or Array
String[] a=new String[]{"one","two","three"}; //Anonmyous array
Stream<String> st1=a.stream();
List<Integer> l=new ArrayList<>();
l.add(1);
l.add(2);
l.add(3);
l.add(4);
Stream<Integer> st2=l.stream();
2. of() - used to create our own stream
Stream<String> st3=Stream.of("one","two","three");
anyMatch(Predicate), allMatch(Predicate), noneMatch(Predicate) - terminal
filter(Predicate) - intermediate - used to filter data based on some condition
reduce() - terminal - used to reduce multiple value into single value
- Optional reduce(BinaryOperator)
- Integer reduce(int initialvalue,BinaryOperator)
- Stream reduce(int initialvalue,BinaryOperator,BinaryOperator)
public class Main {
public static void main(String...args) {
List<String> l=new ArrayList<>();
l.add("Ram");
l.add("Sam");
l.add("Raj");
l.add("Tam");
l.add("Tim");
l.add("Jim");
l.add("Ram");
l.add("Ham");
System.out.println(l.size()); //8
Stream<String> st=l.stream();
Stream<String> st1=st.distinct();
long val=st1.count();
System.out.println(val); //7
long val1=l.stream().distinct().count();
System.out.println(val1); //7
boolean b1=l.stream().distinct().anyMatch((e)->e.startsWith("R"));
System.out.println(b1); //true
boolean b2=l.stream().distinct().allMatch((e)->e.startsWith("R"));
System.out.println(b2); //false
boolean b3=l.stream().distinct().noneMatch((e)->e.startsWith("Z"));
System.out.println(b3); //true
List<Student> l1=new ArrayList<>();
l1.add(new Student(23,"PK"));
l1.add(new Student(26,"KK"));
l1.add(new Student(22,"MK"));
l1.add(new Student(21,"SK"));
l1.add(new Student(20,"AK"));
l1.add(new Student(33,"TK"));
l1.add(new Student(24,"BK"));
l1.add(new Student(25,"GK"));
l1.add(new Student(27,"DK"));
Stream<Student> st2=l1.stream().filter((s1)->s1.getId()>25);
st2.forEach(System.out::println);
Optional opt=Stream.of(3,5,6).reduce((a,b)->a*b);
System.out.println(opt.get()); //90
Integer i=Stream.of(3,5,6).reduce(2, (a,b)->a*b);
System.out.println(i); //180
Optional<String> opt1=Stream.of("lion","ape","tiger").min((c1,c2)->c1.length()-c2.length());
System.out.println(opt1.get()); //ape
Optional<String> opt2=Stream.of("lion","ape","tiger").max((c1,c2)->c1.length()-c2.length());
System.out.println(opt2.get()); //tiger
}
}
map(Function) - intermediate - used to data transformation
- take one Function functional interface as an argument and return a stream consisting of results generated by applying passed function to each element
flatMap(Function) - intermediate - used to data transformation + flattening
- take one Function functional interface as an argument and return a new stream and that stream is copied to another stream which will return the value
collect(Collector) - terminal - used to collect the data in List or Set or Map
Collectors.toList()
Collectors.toSet()
Collectors.toMap(Function f1,Function f2)
Collectors.joining()
Collectors.counting()
Collectors.toCollection(Supplier) - other than List,Set or Map, if we want to collect in different datatype
Collectors.partitioningBy() - used to split the list based on true or false condition
- partitioningBy(Predicate)
- partitioningBy(Predicate, Collector)
Collectors.groupingBy() - used to group the elts based on some condition
- groupingBy(Function)
- groupingBy(Function, Collector)
- groupingBy(Function,Comparator,Collector)
class Customer {
private int id;
private String name;
private String email;
private List<String> phoneNumbers;
public Customer(int id, String name, String email, List<String> phoneNumbers) {
super();
this.id = id;
this.name = name;
this.email = email;
this.phoneNumbers = phoneNumbers;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<String> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(List<String> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
}
public class MapVsFlatMap {
public static List<Customer> getAll() {
return Stream.of(
new Customer(101, "john", john@gmail.com, Arrays.asList("397937955", "21654725")),
new Customer(102, "smith", smith@gmail.com, Arrays.asList("89563865", "2487238947")),
new Customer(103, "peter", peter@gmail.com, Arrays.asList("38946328654", "3286487236")),
new Customer(104, "kely", kely@gmail.com, Arrays.asList("389246829364", "948609467"))
).collect(Collectors.toList());
}
public static void main(String[] args) {
List<Customer> customers = getAll();
//List<Customer> convert List<String> -> Data Transformation
//mapping : customer -> customer.getEmail()
//customer -> customer.getEmail() one to one mapping, since one customer have one email
List<String> emails = customers.stream()
.map(customer -> customer.getEmail())
.collect(Collectors.toList());
System.out.println(emails);
//customer -> customer.getPhoneNumbers() ->> one to many mapping
//customer -> customer.getPhoneNumbers() ->> one to many mapping
List<List<String>> phoneNumbers = customers.
stream().map(customer -> customer.getPhoneNumbers())
.collect(Collectors.toList());
System.out.println(phoneNumbers); //creates stream of phone numbers
//List<Customer> convert List<String> -> Data Transformation
//mapping : customer -> phone Numbers
//customer -> customer.getPhoneNumbers() ->> one to many mapping, since one customer have many phonenumbers
List<String> phones = customers.stream()
.flatMap(customer -> customer.getPhoneNumbers().stream())
.collect(Collectors.toList());
System.out.println(phones); //flattens the phone number and prints
}
}
public class Main {
public static void main(String...args) {
Integer[] a=new Integer[] {1,2,3,4,5};
List<Integer> l=Arrays.asList(a);
System.out.println(l); //[1,2,3,4,5]
//From JDK10
//List<Integer> l1=List.of(1,2,3,4,5);
List<Integer> l1=l.stream().map((e)->e*3).collect(Collectors.toList());
l1.forEach(System.out::println);
List<Integer> l2=l.stream().flatMap((e)->Stream.of(e*2)).collect(Collectors.toList());
l2.forEach(System.out::println);
String str=Stream.of("one","two","three").collect(Collectors.joining("-"));
System.out.println(str); //one-two-three
long c=Stream.of("one","two","three").collect(Collectors.counting());
System.out.println(c); //3
List<String> l3=Stream.of("lions","tigers","bears","toads","toads")
.filter((s)->s.startsWith("t"))
.collect(Collectors.toList());
System.out.println(l3); //[tigers, toads, toads]
List<String> l4=Stream.of("lions","tigers","bears","toads","toads")
.filter((s)->s.startsWith("t")).distinct()
.collect(Collectors.toList());
System.out.println(l4); //[tigers, toads]
Set<String> l5=Stream.of("lions","tigers","bears","toads","toads")
.filter((s)->s.startsWith("t"))
.collect(Collectors.toSet());
System.out.println(l5); //[toads, tigers]
Set<String> l6=Stream.of("lions","tigers","bears","toads","toads","tadpoles")
.filter((s)->s.startsWith("t"))
.collect(Collectors.toSet());
System.out.println(l6); //[toads, tadpoles, tigers]
TreeSet<String> l7=Stream.of("lions","tigers","bears","toads","toads","tadpoles")
.filter((s)->s.startsWith("t"))
.collect(Collectors.toCollection(TreeSet::new));
System.out.println(l7); //[tadpoles, tigers, toads]
Map<String,Integer> m1=Stream.of("lions","tigers","bears","toads")
.collect(Collectors.toMap((k1)->k1, (v1)->v1.length()));
System.out.println(m1); //{toads=5, lions=5, bears=5, tigers=6}
Map<Boolean,List<String>> m2=Stream.of("lions","tigers","bears","toads","toads","tadpoles")
.collect(Collectors.partitioningBy((s1)->s1.length()<=5));
System.out.println(m2);//{false=[tigers, tadpoles], true=[lions, bears, toads, toads]}
Map<Boolean,Set<String>> m3=Stream.of("lions","tigers","bears","toads","toads","tadpoles")
.collect(Collectors.partitioningBy((s2)->s2.length()<=5, Collectors.toSet()));
System.out.println(m3);//{false=[tadpoles, tigers], true=[toads, lions, bears]}
Map<Integer,List<String>> m4=Stream.of("lions","tigers","bears","toads","ape","lions")
.collect(Collectors.groupingBy((e)->e.length()));
System.out.println(m4); //{3=[ape], 5=[lions, bears, toads, lions], 6=[tigers]}
Map<Integer,Set<String>> m5=Stream.of("lions","tigers","bears","toads","ape","lions")
.collect(Collectors.groupingBy((e)->e.length(),Collectors.toSet()));
System.out.println(m5); //{3=[ape], 5=[toads, lions, bears], 6=[tigers]}
}
}
Handson
1. Given a list of integers, find the sum of the squares of all even numbers.
2. Given a list of strings (names), concatenate all names that start with the letter 'A' in uppercase and return the concatenated string.
3. Given a list of strings, find the longest word. If multiple words are of the same length, return the first one.
4. Given a list of strings, count how many times each word appears in the list.
5. Given a list of integers, calculate the average of only the positive numbers.
6. Given a list of integers, find the distinct even numbers.
7. Given a list of integers, find the first odd number greater than 5.
8. Given a list of integers, check if all numbers are positive.
9. Given a list of integers, calculate the sum of squares of even numbers.
10. Write a Stream operation to find the longest string from a list of strings.
No comments:
Post a Comment