dreamsys software

Java 8 Lambda Expressions Tutorial

Don't Repeat Yourself

This next section will cover somewhat of a real world example. Let's say that we have a UserComponent which has several operations that all take a UserRequest object and return a UserResponse object. Imagine that we have some special processing that we want to do before and after each call that is always the same, special processing for validating before performing the request and then some special processing to perform after the request. We would also want to catch any unchecked exceptions that were thrown during the process and handle them as well.

Using the old way, if we wanted to wrap these methods inside of a try catch to ensure that no exceptions were returned by our Adapter class, we would need to have each of the methods contain at the very least our try/catch block. But we can create our method which does all of this checking and then just pass a reference to the methods of our UserComponent object to make the code much simpler and with less code repeating.

First let's take a look at the classes involved:

User.java
public class User {
  Integer id;
  String firstName;
  String lastName;
  Integer age;

  User() {}
  User(int id, String first, String last, int age) {
    this.id = id;
    this.firstName = first;
    this.lastName = last;
    this.age = age;
  }

  public String toString() {
    return "" + id + ", " + firstName + ", " + lastName + ", " + age;
  }
}
UserRequest.java
public class UserRequest {
  User user;

  public UserRequest() {

  }

  public UserRequest(User user) {
    this.user = user;
  }
}
UserResponse.java
import java.util.List;

public class UserResponse {
  List<User> users;
  boolean success = true;

  public UserResponse() {

  }

  public UserResponse(List<User> users) {
    this.users = users;
  }
}

Now the code for our UserComponent interface and some code for a mock implementation.

UserComponent.java
public interface UserComponent {
  UserResponse fetchAllUsers(UserRequest req);
  UserResponse fetchUser(UserRequest req);
  UserResponse deleteUser(UserRequest req);
  UserResponse updateUser(UserRequest req);
  UserResponse insertUser(UserRequest req);
}
MockUserComponent.java
import java.util.*;
import java.util.stream.*;

public class MockUserComponent implements UserComponent {
  List<User> users = new ArrayList<User>();

  public UserResponse fetchAllUsers(UserRequest req) {
    return new UserResponse(users);
  }

  public UserResponse fetchUser(UserRequest req) {
    return new UserResponse(users.stream().filter(u -> u.id.equals(req.user.id)).collect(Collectors.toList()));
  }

  public UserResponse deleteUser(UserRequest req) {
    users = users.stream().filter(u -> (!u.id.equals(req.user.id))).collect(Collectors.toList());
    return new UserResponse();
  }

  public UserResponse updateUser(UserRequest req) {
    User user = users.stream().filter(u -> u.id.equals(req.user.id)).collect(Collectors.toList()).get(0);
    user.firstName = req.user.firstName;
    user.lastName = req.user.lastName;
    user.age = req.user.age;
    return new UserResponse();
  }

  public UserResponse insertUser(UserRequest req) {
    users.add(req.user);
    return new UserResponse();
  }
}

Now we get to the code for our UserComponentAdapter, this class has a method callComponent which takes as a parameter a function that takes UserRequest as a parameter and returns a UserResponse. So we can simply pass our UserComponent functions to this method directly.

UserComponentAdapter.java
import java.io.IOException;
import java.util.*;
import java.util.function.*;

public class UserComponentAdapter {
  UserComponent uc = new MockUserComponent();

  UserResponse callComponent(UserRequest request, Function<UserRequest, UserResponse> func) {
    try {
      //Special validation function which validations the request object.

      UserResponse response = func.apply(request);

      //Special response handling that checks all response properties and
      //performs logging and/or other operations.

      return response;
    } catch(Exception e) {
      UserResponse response = new UserResponse();
      //special code for applying error information into the response object.
      return response;
    }
  }

  List<User> fetchAllUsers() throws IOException {
    return callComponent(new UserRequest(), uc::fetchAllUsers).users;
  }

  User fetchUser(Integer id) throws IOException {
    return callComponent(new UserRequest(new User(id, "", "", 0)), uc::fetchUser).users.get(0);
  }

  boolean deleteUser(User user) throws IOException {
    return callComponent(new UserRequest(user), uc::deleteUser).success;
  }

  boolean updateUser(User user) throws IOException {
    return callComponent(new UserRequest(user), uc::updateUser).success;
  }

  boolean insertUser(User user) throws IOException {
    return callComponent(new UserRequest(user), uc::insertUser).success;
  }
}

Notice how we get a reference to the method by using the objectName::methodName.


Prev (Listeners) | Next (TOC)


Blog Entries
Blob Entry 1
Blob Entry 2
Blob Entry 3
Blob Entry 4
Blob Entry 5
Blob Entry 6