Pages

Sunday, April 10, 2022

How to convert Roman numbers to Integer ?



package java8.algorithemic;

import java.util.HashMap;
import java.util.Map;

public class RomanToInteger {

    private static Map<Character, Integer> romanIntegerMap = new HashMap<>(7);

    static {
        romanIntegerMap.put('I', 1);
        romanIntegerMap.put('V', 5);
        romanIntegerMap.put('X', 10);
        romanIntegerMap.put('L', 50);
        romanIntegerMap.put('C', 100);
        romanIntegerMap.put('D', 500);
        romanIntegerMap.put('M', 1000);
    }

    public int romanToInt(String s) {
        char[] charArray = s.toCharArray();
        int intValue = 0;
        char beforeChar = '\u0000';
        for(int i = 0; i < charArray.length; i++) {
            intValue += getBaseIntegerForRoman(beforeChar, charArray[i]);
            beforeChar = charArray[i];
        }
        return intValue;
    }

    public int getBaseIntegerForRoman(char beforeChar, char currentChar) {
        if (currentChar == 'V' && beforeChar == 'I') {
            return getCurrentValue(currentChar, beforeChar);
        } if (currentChar == 'X' && beforeChar == 'I') {
            return getCurrentValue(currentChar, beforeChar);
        } else if (currentChar == 'L' && beforeChar == 'X') {
            return getCurrentValue(currentChar, beforeChar);
        } else if (currentChar == 'C' && beforeChar == 'X') {
            return getCurrentValue(currentChar, beforeChar);
        } else if (currentChar == 'D'&& beforeChar == 'C') {
            return getCurrentValue(currentChar, beforeChar);
        } else if (currentChar == 'M' && beforeChar == 'C') {
            return getCurrentValue(currentChar, beforeChar);
        } else {
            int val = getBaseIntegerForRoman(currentChar);
            return val;
        }
    }

    public int getCurrentValue(char currentChar, char beforeChar) {
        int beforeVal  = getBaseIntegerForRoman(beforeChar);
        int currentVal = getBaseIntegerForRoman(currentChar) - beforeVal;
        return currentVal - beforeVal;
    }

    public int getBaseIntegerForRoman(char ch) {
        return this.romanIntegerMap.get(ch);
    }
}


Test class as follows.

package java8.algorithemic;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class RomanToIntegerTest {
    @Test
    public void test() {
        RomanToInteger romanToInteger = new RomanToInteger();
        Assertions.assertEquals(4,romanToInteger.romanToInt("IV"));
        Assertions.assertEquals(9,romanToInteger.romanToInt("IX"));
        Assertions.assertEquals(13,romanToInteger.romanToInt("XIII"));
        Assertions.assertEquals(18,romanToInteger.romanToInt("XVIII"));
        Assertions.assertEquals(19,romanToInteger.romanToInt("XIX"));
        Assertions.assertEquals(4500,romanToInteger.romanToInt("MMMMD"));
        Assertions.assertEquals(90,romanToInteger.romanToInt("XC"));
        Assertions.assertEquals(80,romanToInteger.romanToInt("LXXX"));
    }
}

Saturday, April 2, 2022

How to use Java Optional

The most common and frequent exception which many Java developers encounter is NullPointerException.  Though this is very common exception and the fix is also straightforward for most of the developers. They simply put null check or nested null checks in order to avoid happening this exception. This actually increases the number of indentation level in your code and also reduces the readability too. Even if you avoid happening this exception in this way, the complete flow might not be consistence with all client codes. If you fix this exception with simple null check,  you need to make sure that the complete flow executes correctly as per business requirement without producing strange results from the application. 

And also, there are many situations where, you add this null check only after happening the NullPointerException at least a once only. Yes, some developers proactively check the presence and absence of a value of variable before it is accessed and write the complete flow which handles the absence of the value. 

Java 8 introduces java.util.Optional<T> to represent the absence of a value in a particular variable or a field of any type in more precise and safer manner. This enforces developers to specifically focus on the absence of the value of their reference, a variable or return type of a method.  So defining a method to accept an optional or a method to return an optional indicates that the value of that variable may not be presence. There is a possibility of absence of the value. Your peer developers or in future, if someone is going to modify the code or use those methods by different client code, they will know that the value of the reference can be absence and should write the client code according to that. 

Assume the following are two methods of a data access class for Employee entity.
    public Employee findEmployeeByName(String name) {
        Employee emp = null; // code get employee from DB or somewhere.
        return emp;
    }

    public Optional<Employee> findEmployeeOptionalByName(String name) {
        Employee emp = null; // code to get employee from DB or somewhere
        return Optional.ofNullable(emp);
    }

Both method is to find an employee for a given employee name. Let's say both scenario, system could not find an employee for the given name and both method returns value absence reference (null). The first method returns null. But the second method, in stead of returning null, it returns an empty optional which indicates all clients codes that, the return value in the returned variable may or may not presence and write your client code according to that. Let's look two client code for both above method.
 
    //Client code1
    Employee emp = employeeRepository.findEmployeeByName("David");
    System.out.print(emp.getName());

    //Client code2
    Optional<Employee> employeeOptional = employeeRepository.findEmployeeOptionalByName("David");
    System.out.println(employeeOptional.get().getName());	

In the above code, first client code end with NullPointerException and the second client code ends with NoSuchElementException. Off-course, in the first client code, developers may directly access 'emp' object without checking the absence of the value which results NullPointerException and then later on, they will add null check before accessing 'emp' object. This is the old practice that most developers were doing.

But, how about the second client code2 which is also not the best way to unwrap an optional. The 'findEmployeeOptionalByName()' method returns an Optional of Employee which indicates that the value may not be present. The developers should write the client code to handle the absent of the value in this case. It is a developer's responsibility and good practice too. 

How, optional is unwrapped in the above client code2 is not a best way of doing. If particular method returns an optional means, developers need to specifically focus on it and write the code appropriately. The above code does not leverage the purpose of Optional. 

There are several ways to unwrap an Optional. Using get() method of Optional is not a good idea every time, unless you know the the presence and absence of the value of the optional. For empty optional, this will return NoSuchElementException exception. The optional's ifPresent() method and also for default values, orElse() method are good choices in order to unwrap an optional and get the value. Look at the following code.

    //unwrap optional with isPresent() method
    if(employeeOptional.isPresent()) {
       System.out.println(employeeOptional.get().getName());
    }

    //unwrap optional with orElse() method
    String empName = employeeOptional.map(Employee::getName).orElse("Unknown");
    System.out.print(empName);
As in the above second approach, you can apply map() method to an optional in order to transform optional into a different type. In this case, Employee optional to a string. If optional is empty, it will execute default orElse() method. Further you have orElseGet() method which accepts a supplier than using orElse(). The orElseGet() is more efficient than orElse(), because the code within the supplier argument will be executed only if optional value is not present. Let's say, you have to do some expensive thing, if  optional value is not presence, orElseGet() method is best suited.
String empName = employeeOptional.map(Employee::getName).orElseGet(() -> "Unknnow"); System.out.println(empName);
If you want to throw an exception, in case of optional value is absence, you can use orElseThrow() method as follows. The advantage of using this method is, you can throw any exception type that you preferred.

      String empName = employeeOptional.map(Employee::getName).orElseThrow(() -> new RuntimeException("Unable to find employee"));
      System.out.print(empName);
You can apply map(), flatMap() and filter() methods to an optional similar as stream API.

Thursday, February 3, 2022

Java Function example use case

Java Function<T, R> is functional interface which accepts one type of argument and return a result. We can leverage java Function to write more maintainable codes. For example, let's say, we are going to develop an API or service method to place an order for the customer. After successful placement of order, the service method should send a notification to the customer. At this moment, we have two ways of sending notification, ie: SMS and  email.  But, we don't know, in future, we might need to add more notification methods. 
If we don't write this method in clear and maintainable manner, we have to modify this service method every time in order to add a new notification method. 

First, we will see, the solution for this using object oriented approach and then we will improve the code using Java Function in a functional way. 

As usual, let's define an interface as follows.

public interface Notifier {
    void notify(Order order);
}

Then we need two concrete classes for each type of notification method. As follows, we need to create a new concrete class for each notification method.

public class SmsNotifier implements Notifier {
    @Override
    public void notify(Order order) {
        //code to send sms notification
    }
}


public class EmailNotifier implements Notifier {
    @Override
    public void notify(Order order) {
        // Code to send email notification
    }
}

Let's write some sample client code in order to place an order
     
//OOP approch
//Assume we have an instanc eof order service
OrderService orderService = ...
//Assume we have the order object
Order order = ...
//Assume we have the customer object
Customer customer = ....

Notifier notifier = null;
if (customer.getNotificationPreference().equals("SMS")) {
    notifier = new SmsNotifier();
} else {
    notifier = new EmailNotifier();
}

orderService.placeOrder(order, notifier);
     
  
This disadvantage of above approch is, we have to create a concrete class for each new notification method. Let's see, how we can improve the code using java Function. Let's make 'Notifier' a functional interface. We simply add @FunctionalInterface annotation.

@FunctionalInterface
public interface Notifier {
    void notify(Order order);
}

The client code using java lambda expression is as follows.

// functional approach.
if (customer.getNotificationPreference().equals("SMS")) {
    orderService.placeOrder(order, (Order odr) -> {
      //code to send SMS
    });
} else {
    orderService.placeOrder(order, (Order odr) -> {
     //code toe send email
    });
}
With the functional programming approch, we don't want to create a new class for each new notification method. You need to decide which approch to use based on your use case or scope of different strategy. If it is small piece of code that you want to customize, you can go with functional approch using java lambda.

Sunday, January 30, 2022

How to group list of objects using java lambda

Let's consider the following POJO class.
public class Dish {

	private String name;
	private Boolean vegitarian;
	private Integer calories;
	private DishType type;

}

Java 8 stream API provides plenty of features to group objects into different buckets. Let's say, we want to group list of Dish objects based on the amount of calories. We will define an enum constant to declare different calory categories. 


public enum CaloryLevel {
    DIET,
    NORMAL,
    FAT;
}

The Calory level is not an attribute of Dish class. The calory level is defined by using the amount of calories from Dish class which is an attribute of Dish class, ie: 'calories'. If the amount of calory is less than 400, the calory level is 'DIET'. If the amount of calory is between 400 and 700, the calory level is 'NORMAL'. If the calory amount is above 700, the calary level is defined as 'FAT'. The legacy approch of grouping list of objects is as follows. It generally uses a map to put objects into different buckets.


public static void groupDishByCaloriAmountLegacyApproch(List<Dish> menu) {

	Map<CaloryLevel, List<Dish>> dishOverCaloryLevel = new HashMap<CaloryLevel, List<Dish>>();

	for(CaloryLevel caloryLevel : CaloryLevel.values()) {
		dishOverCaloryLevel.put(caloryLevel, new ArrayList<Dish>());
	}

	for(Dish dish : menu) {
		if (dish.getCalaries() <= 400) {
			dishOverCaloryLevel.get(CaloryLevel.DIET).add(dish);
		} else if (dish.getCalaries() <= 700) {
			dishOverCaloryLevel.get(CaloryLevel.NORMAL).add(dish);
		} else {
			dishOverCaloryLevel.get(CaloryLevel.FAT).add(dish);
		}
	}
}

Now, let's see, how we can improve the above code using Java 8 features. We can get the same output by using Java stream API provided methods. See the following code.

Map<CaloryLevel, List<Dish>> dishOverCaloryLevel = menu.stream().collect(Collectors.groupingBy((Dish d) -> {
	if (d.getCalaries() <= 400) {
		return CaloryLevel.DIET;
	} else if (d.getCalaries() <= 700) {
		return CaloryLevel.NORMAL;
	} else
		return CaloryLevel.FAT;
	}
));
Again, the calory level is not an attribute of Dish class. That attribute is external one which is defined by using the amount of calories. If we want to get the calory level by using the amount calories which is defined within the Dish class, we have to write boilaplate codes as in the above method. As a best coding practice, defining the calory level can be added into the Dish class itself as method. The new Dish class is as follows.

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Dish {

	private String name;
	private Boolean vegitarian;
	private Integer calaries;
	private DishType type;

	private CaloryLevel getCaloryLevel() {
		if (this.getCalaries() <= 400) {
			return CaloryLevel.DIET;
		} else if (this.getCalaries() <= 700) {
			return CaloryLevel.NORMAL;
		} else {
			return CaloryLevel.FAT;
		}
	}
}

The complete lambda expresion which was passed into the 'Collectors.groupingBy' method, now it is defined as a method inside the Dish class itself. We can now use Java 8's method referene to simply the code more as follows. Now the code to group list of Dish objects has narrowed down into a single like.

Map<CaloryLevel, List<Dish>> dishOverCaloryLevel1 = menu.stream().collect(Collectors.groupingBy(Dish::getCaloryLevel));

How to replace anonymous class with Java 8 lambda

Java lambda expression can be used to replace legacy anonymous class. For example, let's consider the following POJO class.

public class Dish {

	private String name;
	private Boolean vegitarian;
	private Integer calories;
	private DishType type;

}
Let's say, we have a list of objects from the above class and we want to sort them by name. The normal approch to sort this kind of custom object list is, using a comparator. So, we can write a comparator as follows.

Comparator<Dish> comparator = new Comparator<Dish>() {
         @Override
         public int compare(Dish o1, Dish o2) {
             return o1.getName().compareTo(o2.getName()); // ASC order
             //return o2.getName().compareTo(o1.getName()); // DESC order
         }
};

With Java's lambda, we can get rid of anonymous class comparator and reduce the code to a single like as follows.

Comparator<Dish> comparator = Comparator.comparing(Dish::getName);

And we can sort the list of Dish's as following.

Collections.sort(menu, comparator);

Share

Widgets