Showing posts with label Java 8. Show all posts
Showing posts with label Java 8. Show all posts

Wednesday

Some advices on using Optional

//DON'T
Optional<User> user = null;
//DO
Optional<User> user =  Optional.empty();

//Don't confuse Optional.of() and Optional.ofNullable(). Choose the right one.

//DON'T
return Optional.ofNullable("EDA");
//DO
return Optional.of("EDA"); //no risk for NPE of using of() method so choose this.

//DON'T
String parameterToMethod = ...; // can be null
return Optional.of(parameterToMethod);//can throw NPE if parameter is null
//DO
String parameterToMethod = ...; // can be null
return Optional.ofNullable(parameterToMethod);//no risk for NPE

//DON'T
String userName = ... ;
return Optional.ofNullable(userName).orElse("EDA");
//DO
String userName = ... ;
return userName == null ? "EDA" : userName; // choose always the simplest one for such easy cases

//DON'T
Optional<String> user = ...; //can be empty
String myUser = user.get(); // can throw NoSuchElementException if user is empty
//DO
Optional<String> user = ...; //can be empty
if(user.isPresent()) {
 String myUser = user.get();
}


//DON'T
Optional<String> userName = ...;
if(userName.isPresent()) {
   return userName.get();
} else {
   return "Unknown person";
}
//DO
Optional<String> userName = ...;
return userName.orElse("Unknown person");

// DON'T
Optional<String> parameterUserName = ... ;
Optional<String> userName = Optional.of("EDA");
if(parameterUserName.isPresent()) {
 return parameterUserName;
} else {
 return userName;
}
//DO
Optional<String> parameterUserName = ... ;
Optional<String> userName = Optional.of("EDA");
return parameterUserName.or(() -> userName); // with java 9

// DON'T
Optional<String> userName = ... ;
if(userName.isPresent()) {
    System.out.println("userName: " + userName.get());
} else {
    System.out.println("User not found");
}
//DO - java 9
Optional<String> userName = ... ;
userName.ifPresentOrElse(
    System::out::println, 
    () -> System.out.println("User not found")
};

//DON'T
Optional<String> userName = ...;
if (userName.isPresent()) {
    System.out.println("userName: " + userName.get());
}
//DO
Optional<String> userName = ...;
userName.ifPresent(System.out::println);

//DON'T
Optional<String> userName = ...;
if(userName.isPresent()) {
 return userName.get();
} else {
 throw new NoSuchElementException(); 
}
//DO
Optional<String> userName = ...;
return userName.orElseThrow(); //java 10
return userName.orElseThrow(YourException::new);//java 8-9 

//DON'T
 .......
 .filter(Optional::isPresent)
        .map(Optional::get)
 .collect(toList());
//DO
 .......
 .flatMap(Optional::stream)
 .collect(toList());

// AVOID
Optional<Integer> opt = Optional.of(10);
Optional<Long> opt = Optional.of(20L);
Optional<Double> opt = Optional.of(20.53d);

// PREFER
OptionalInt opt = OptionalInt.of(10);           // opt.getAsInt()
OptionalLong opt = OptionalLong.of(20L);        // opt.getAsLong()
OptionalDouble opt = OptionalDouble.of(20.53d); // opt.getAsDouble()

Monday

Optional in java 8 & 9

I'll try to give example for Optional class which has came up for NullPointerException. It is a wrapper class, it can contain any other Object or it can be empty. Java 8 features:

Create Optional instances:
//You can create an empty Optional instance.
Optional.empty();
 
//of() method will throw NullPointerException if the user is null
//you should use of() method only if you are sure that your object is not null
Optional<User> opt = Optional.of(user);

//ofNullable() method can be use if the user object is null or not null.
Optional<User> opt = Optional.ofNullable(user);

Retrieve the actual object inside Optional instance:
//you can use get() method but if the user object is null then it will throw NoSuchElementException.
Optional<User> opt = Optional.ofNullable(user);
User myUser = opt.get();

//so, you should first check the value is present or not
//isPresent() method can be use
Optional<User> opt = Optional.ofNullable(user);
if(opt.isPresent()) {
 User myUser = opt.get();
 //your other jobs
}

//There is also ifPresent() method which combines isPresent() and get()
//lambda expression is used
Optional<User> opt = Optional.ofNullable(user);
opt.ifPresent(myUser -> {
    ///your other jobs
})

Return values:
//orElse() method returns the values if it's present, if not present then returns the other argument
//if user is not null then returns it. Otherwise returns user2.
User myUser = Optional.ofNullable(user).orElse(user2);


//orElseGet() method returns the values if it's present,
//if not present then executes Supplier interface
User myUser = Optional.ofNullable(user).orElseGet( () -> user2);

Lets see the difference between orElse() and orElseGet().
In the following example object is null and both return the other object. There is no difference as you see but....
User user = null; 
System.out.log("orElse>> ");
User myUser = Optional.ofNullable(user).orElse(createUser());
System.out.log(myUser.getName());
System.out.log("orElseGet>> ");
User myUser = Optional.ofNullable(user).orElseGet( () -> createUser());
System.out.log(myUser.getName());

...
private User createUser() {
    logger.debug("createUser method inside");
    return new User("eda2");
}

/*
 Output:
  orElse>>
  createUser method inside
  eda2
  orElseGet>>
  createUser method inside
  eda2
*/

In the following example object is not null.
But even if object is not null orElse() method has gone createUser() method.
orElse() always will call the given function() but orElseGet() will call only if optional is not present.
So orElse() is very expensive for the resources!!!!!!
User user = new User("eda"); 
System.out.log("orElse>> ");
User myUser = Optional.ofNullable(user).orElse(createUser());
System.out.log(myUser.getName());
System.out.log("orElseGet>> ");
User myUser = Optional.ofNullable(user).orElseGet( () -> createUser());
System.out.log(myUser.getName());

...
private User createUser() {
    logger.debug("createUser method inside");
    return new User("eda2");
}

/*
 Output:
  orElse>>
  createUser method inside
  eda
  orElseGet>>
  eda
*/

Return exception:
//orElseThrow() throws an exception if the object is empty:
User myUser = Optional.ofNullable(user).orElseThrow(() -> new UserDoesNotExist());

Mapping:
//map() method applies the functional argument to the value and returns the result.
User user = new User("eda"); 
String userName = Optional.ofNullable(user)
 .map(myUser -> myUser.getName()).orElse("DEFAULT NAME");

//if the get method returns an Optional value you can use flatMap() and return unwrapped String value.
public class User {    
    private String name;

    public Optional<String> getName() {
        return Optional.ofNullable(name);
    }

}

User user = new User("eda");
String userName = Optional.ofNullable(user)
 .flatMap(myUser -> myUser.getName()).orElse("DEFAULT NAME");

Filtering:
//filter() method
//optUser will not contain a null name value.
User user = new User(null);
Optional<User> optUser = Optional.ofNullable(user)
  .filter(myUser -> myUser.getName() != null);

//optUser.isPresent() is false, in this case filter returns empty Optional.

Features that come with Java 9 to Optional class:
Java 9 added 3 more methods to the Optional class:  or(), ifPresentOrElse() and stream().
or() method:
//orElse() and orElseGet() methods returns unwrapped values.
//or() method is similar with them but it returns Optional object.
User user = "eda"; 
Optional<User> myUser = Optional.ofNullable(user).or(() -> createUser());
//User myUser = Optional.ofNullable(user).or(() -> createUser()).get();
System.out.log(myUser.get().getName());
System.out.log("**");
...

User user = null; 
Optional<User> myUser = Optional.ofNullable(user).or(() -> createUser());
System.out.log(myUser.get().getName());
...

private Optional<User>  createUser() {
    logger.debug("createUser method inside");
    return Optional.of(new User("eda2"));
}

/*
 Output:
  eda
  **
  createUser method inside
  eda2
*/

ifPresentOrElse() method:
It gives us a change to run a function if the optional is empty.
Optional<User> opt = Optional.ofNullable(user);
opt.ifPresentOrElse(myUser -> 
    ///your other jobs, myUser.getName()
 , () -> logger.info("User not found")
);

stream() method:
I'll mention about stream in an another writing.
User user = new User("eda");
List<String> nameList = Optional.ofNullable(user)
   .stream()
   .filter(u -> u.getName() != null)
   .map(u -> u.getName())
   .collect(Collectors.toList());

Tuesday

Sort multiple variables with Java 8 stream

I'll try to sort my data as following rules using java 8 stream.
Student.Address.CountryName = B or C is previous  >>
    then Student.StudentDetail.StudentScore descending (nulls  appear at the end) >>
       then Student.StudentDetail.RegistrationTime ascending

Example data:

The following code snippet makes sorting: 
 studentList.stream().sorted(
               Comparator.comparing((Student s)-> !Arrays.stream(priorityCountryName).anyMatch(s.address.getCountryName()::equals))
               .thenComparing(Comparator.comparing(s-> s.studentDetail.getStudentScore(), Comparator.nullsLast(Comparator.reverseOrder())))
               .thenComparing((s1) -> s1.studentDetail.getRegistrationTime())
)

Full example:
import java.io.Serializable;

public class Student implements Serializable {
    
    public final Address address;
    public final StudentDetail studentDetail;
    
    public Student(Address address, StudentDetail studentDetail) {
        this.address = address;
        this.studentDetail = studentDetail;
    }
}
import java.io.Serializable;

public class Address implements Serializable {
    
    private String countryName;
    
    public Address() {
    }

    public String getCountryName() {
        return countryName;
    }

    public void setCountryName(String countryName) {
        this.countryName = countryName;
    }

}
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Timestamp;

public class StudentDetail implements Serializable {

    private int studentNumber;
    private BigDecimal studentScore;
    private Timestamp registrationTime;
    
    public StudentDetail(){
    }

    public BigDecimal getStudentScore() {
        return studentScore;
    }

    public void setStudentScore(BigDecimal studentScore) {
        this.studentScore = studentScore;
    }

    public Timestamp getRegistrationTime() {
        return registrationTime;
    }

    public void setRegistrationTime(Timestamp registrationTime) {
        this.registrationTime = registrationTime;
    }

    public int getStudentNumber() {
        return studentNumber;
    }

    public void setStudentNumber(int studentNumber) {
        this.studentNumber = studentNumber;
    }
    
}
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class Test {

    public static void main(String[] args) {
       String[] priorityCountryName = {"B", "C"};
 
       List<Student> studentList = addStudents();
       logStudentList("********studentList mix order**********", studentList);

       List<Student> orderedStudentList = studentList.stream().sorted(
               Comparator.comparing((Student s)-> !Arrays.stream(priorityCountryName).anyMatch(s.address.getCountryName()::equals))
               .thenComparing(Comparator.comparing(s-> s.studentDetail.getStudentScore(), Comparator.nullsLast(Comparator.reverseOrder())))
               .thenComparing((s1) -> s1.studentDetail.getRegistrationTime())
           ).collect(Collectors.toList());;
 
       logStudentList("********studentList ordered**********", orderedStudentList);
    }
    
    
    private static List<Student> addStudents() {
       List<Student> studentList = new ArrayList<Student>();
 
       Student student8 = new Student(new Address(), new StudentDetail());
       student8.address.setCountryName("D");
       student8.studentDetail.setStudentScore(new BigDecimal(5.0).setScale(2, BigDecimal.ROUND_HALF_EVEN));
       student8.studentDetail.setRegistrationTime(Timestamp.valueOf("2024-12-31 09:30:00"));
       student8.studentDetail.setStudentNumber(8);
       studentList.add(student8);
 
       Student student3 = new Student(new Address(), new StudentDetail());
       student3.address.setCountryName("B");
       student3.studentDetail.setStudentScore(new BigDecimal(0.1).setScale(2, BigDecimal.ROUND_HALF_EVEN));
       student3.studentDetail.setRegistrationTime(Timestamp.valueOf("2019-12-31 09:30:00"));
       student3.studentDetail.setStudentNumber(3);
       studentList.add(student3);
 
       Student student5 = new Student(new Address(), new StudentDetail());
       student5.address.setCountryName("B");
       student5.studentDetail.setStudentScore(null);
       student5.studentDetail.setRegistrationTime(Timestamp.valueOf("2018-12-31 09:30:00"));
       student5.studentDetail.setStudentNumber(5);
       studentList.add(student5);
 
       Student student2 = new Student(new Address(), new StudentDetail());
       student2.address.setCountryName("C");
       student2.studentDetail.setStudentScore(new BigDecimal(2.0).setScale(2, BigDecimal.ROUND_HALF_EVEN));
       student2.studentDetail.setRegistrationTime(Timestamp.valueOf("2021-12-31 09:30:00"));
       student2.studentDetail.setStudentNumber(2);
       studentList.add(student2);
 
       Student student7 = new Student(new Address(), new StudentDetail());
       student7.address.setCountryName("D");
       student7.studentDetail.setStudentScore(new BigDecimal(5.0).setScale(2, BigDecimal.ROUND_HALF_EVEN));
       student7.studentDetail.setRegistrationTime(Timestamp.valueOf("2023-12-31 09:30:00"));
       student7.studentDetail.setStudentNumber(7);
       studentList.add(student7);
 
       Student student4 = new Student(new Address(), new StudentDetail());
       student4.address.setCountryName("B");
       student4.studentDetail.setStudentScore(new BigDecimal(0.1).setScale(2, BigDecimal.ROUND_HALF_EVEN));
       student4.studentDetail.setRegistrationTime(Timestamp.valueOf("2020-12-31 09:30:00"));
       student4.studentDetail.setStudentNumber(4);
       studentList.add(student4);
 
       Student student9 = new Student(new Address(), new StudentDetail());
       student9.address.setCountryName("D");
       student9.studentDetail.setStudentScore(new BigDecimal(4.0).setScale(2, BigDecimal.ROUND_HALF_EVEN));
       student9.studentDetail.setRegistrationTime(Timestamp.valueOf("2025-12-31 09:30:00"));
       student9.studentDetail.setStudentNumber(9);
       studentList.add(student9);
 
       Student student1 = new Student(new Address(), new StudentDetail());
       student1.address.setCountryName("B");
       student1.studentDetail.setStudentScore(new BigDecimal(6.0).setScale(2, BigDecimal.ROUND_HALF_EVEN));
       student1.studentDetail.setRegistrationTime(Timestamp.valueOf("2022-12-31 09:30:00"));
       student1.studentDetail.setStudentNumber(1);
       studentList.add(student1);
 
       Student student10 = new Student(new Address(), new StudentDetail());
       student10.address.setCountryName("D");
       student10.studentDetail.setStudentScore(null);
       student10.studentDetail.setRegistrationTime(Timestamp.valueOf("2018-11-12 09:30:00"));
       student10.studentDetail.setStudentNumber(10);
       studentList.add(student10);
 
       Student student6 = new Student(new Address(), new StudentDetail());
       student6.address.setCountryName("E");
       student6.studentDetail.setStudentScore(new BigDecimal(5.0).setScale(2, BigDecimal.ROUND_HALF_EVEN));
       student6.studentDetail.setRegistrationTime(Timestamp.valueOf("2023-12-01 09:30:00"));
       student6.studentDetail.setStudentNumber(6);
       studentList.add(student6);
 
       return studentList;
    }
    
    private static void logStudentList(String firstMessage, List<Student> studentList) {
       System.out.println(firstMessage);
 
       for(Student student : studentList) {
          StringBuilder studentBuilder = new StringBuilder();
        
          studentBuilder.append("countryname: ");
          studentBuilder.append(student.address.getCountryName());
          studentBuilder.append(" studentNumber: ");
          studentBuilder.append(student.studentDetail.getStudentNumber());
          studentBuilder.append(" studentScore: ");
          studentBuilder.append(student.studentDetail.getStudentScore());
          studentBuilder.append(" registrationTime: ");
          studentBuilder.append(student.studentDetail.getRegistrationTime());
        
          System.out.println(studentBuilder.toString());
       }
    }

}

//CONSOLE OUTPUT:
********studentList mix order**********
countryname: D studentNumber: 8 studentScore: 5.00 registrationTime: 2024-12-31 09:30:00.0
countryname: B studentNumber: 3 studentScore: 0.10 registrationTime: 2019-12-31 09:30:00.0
countryname: B studentNumber: 5 studentScore: null registrationTime: 2018-12-31 09:30:00.0
countryname: C studentNumber: 2 studentScore: 2.00 registrationTime: 2021-12-31 09:30:00.0
countryname: D studentNumber: 7 studentScore: 5.00 registrationTime: 2023-12-31 09:30:00.0
countryname: B studentNumber: 4 studentScore: 0.10 registrationTime: 2020-12-31 09:30:00.0
countryname: D studentNumber: 9 studentScore: 4.00 registrationTime: 2025-12-31 09:30:00.0
countryname: B studentNumber: 1 studentScore: 6.00 registrationTime: 2022-12-31 09:30:00.0
countryname: D studentNumber: 10 studentScore: null registrationTime: 2018-11-12 09:30:00.0
countryname: E studentNumber: 6 studentScore: 5.00 registrationTime: 2023-12-01 09:30:00.0
********studentList ordered**********
countryname: B studentNumber: 1 studentScore: 6.00 registrationTime: 2022-12-31 09:30:00.0
countryname: C studentNumber: 2 studentScore: 2.00 registrationTime: 2021-12-31 09:30:00.0
countryname: B studentNumber: 3 studentScore: 0.10 registrationTime: 2019-12-31 09:30:00.0
countryname: B studentNumber: 4 studentScore: 0.10 registrationTime: 2020-12-31 09:30:00.0
countryname: B studentNumber: 5 studentScore: null registrationTime: 2018-12-31 09:30:00.0
countryname: E studentNumber: 6 studentScore: 5.00 registrationTime: 2023-12-01 09:30:00.0
countryname: D studentNumber: 7 studentScore: 5.00 registrationTime: 2023-12-31 09:30:00.0
countryname: D studentNumber: 8 studentScore: 5.00 registrationTime: 2024-12-31 09:30:00.0
countryname: D studentNumber: 9 studentScore: 4.00 registrationTime: 2025-12-31 09:30:00.0
countryname: D studentNumber: 10 studentScore: null registrationTime: 2018-11-12 09:30:00.0