Improve your Java code using - Stream API - Part 3
In this third part of the Stream Api series, let’s talk about the method references and explore its types.
As name suggests, they are similar to object references, but references to a method as well.
As you already know, we can pass behavior as parameters. But, you keep in your mind, there is no difference between method and lambda expression. So, method references are shortened versions of lambda expressions tha call a specific method.
Let’s say you have a Consumer as defined below:
Consumer<String> consumer = str -> System.out.println(str);
This can be written as:
Consumer<String> consumer = System.out::println;
Let’s take a look into another example. Now we have a Function<T,R>functional interface as defined
Function<People, Integer> function = f -> f.getAge();
This can be written as:
Function<People, Integer> function = People::getAge;
4 types of method references
1. Static Methods
This is the syntax for a static methods as method reference:
ClassName::MethodName
To make it more explicit and easy to understand, let’s take a look a new example.
In the below example, we have a method getLength()
which returns the length of the String
.
import java.util.ArrayList;
import java.util.List;
public class StreamMethodRef {
public static int getLength(String str){
return str.length();
}
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("work");
list.add("read");
list.add("practice");
list.add("write");
// Code without using method reference.
list.stream()
.mapToInt(str -> StreamMethodRef.getLength(str))
.forEach(System.out::println);
// Code with method reference.
list.stream()
.mapToInt(StreamMethodRef::getLength)
.forEach(System.out::println);
}
}
2. Instance method of a particular object
Instance method as a method reference have this syntax
ReferenceVariable::MethodName
Let’s take a look at the same example, but now the getLength()
method is not static.
import java.util.ArrayList;
import java.util.List;
public class StreamMethodRef {
public int getLength(String str){
return str.length();
}
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("work");
list.add("read");
list.add("practice");
list.add("write");
StreamMethodRef example = new StreamMethodRef();
// Code without using method reference.
list.stream()
.mapToInt(str -> StreamMethodRef.getLength(str))
.forEach(System.out::println);
// Code with method reference.
list.stream()
.mapToInt(StreamMethodRef::getLength)
.forEach(System.out::println);
}
}
3. Instance method of an arbitrary object
This type of reference method can directly use the class name in the method reference. He does not require the object of the referenced class.
import java.util.ArrayList;
import java.util.List;
public class StreamMethodRef {
public int getLength(String str) {
return str.length();
}
public static void main(String[] args) {
List<Employee> list = new ArrayList<>();
list.add(new Employee("Sergio", 23, 20000));
list.add(new Employee("Ruy", 18, 40000));
list.add(new Employee("Julia", 54, 100000));
list.add(new Employee("Andressa", 5, 34000));
list.add(new Employee("Ashley", 63, 54000));
// Code without using method reference
int totalSalary1 = list.stream()
.mapToInt(emp -> emp.getSalary())
.sum();
// Code with method reference
int totalSalary = list.stream()
.mapToInt(Employee::getSalary)
.sum();
System.out.println("The total salary is " + totalSalary);
}
}
class Employee {
String name;
int age;
int salary;
Employee(String name, int age, int salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public int getSalary() {
return salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
4. Constructor references
With a new key word, we can refer to a constructor in the same way we reference a static method.
import java.util.ArrayList;
import java.util.List;
public class StreamMethodRef {
public int getLength(String str) {
return str.length();
}
public static void main(String[] args) {
List<Employee> list = new ArrayList<>();
list.add("Sergio");
list.add("Ruy");
list.add("Julia");
list.add("Andressa");
list.add("Dora");
// Code without constructor reference
list.stream()
.map(name -> new Employee(name))
.forEach(System.out::println);
// Code with constructor reference
list.stream()
.map(Employee::new)
.forEach(System.out::println);
}
}
class Employee {
String name;
int age;
int salary;
Employee(String name) {
this.name = name;
}
Employee(String name, int age, int salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public int getSalary() {
return salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
Conclusion
Method references in Java provide a clear, and concise way to represent method calls within the scope of functional interfaces. Not only does this enhance the readability of your code, but it also simplifies the syntax. Remember, practice is the key to mastering these concepts.
As always, happy coding!