Scala Partial Function

A partial function is a function that is valid for only a subset of values of those types you might pass in to it.

Partial function can be defined by using ‘case’ statement.

Let us define a partial function and to know how to use it.


  val multiplyBy100: PartialFunction[Int, Int] = {
    case x if x > 0 => x * 100
  }

The above partial function gets an integer value as input and process it and returns another integer value. Here, we check the value is negative or not before applying multiple operation.

Consider that we have a list of numbers and want to multiply each value by value 100, then we can make use of the above function.

Partial functions can help us to get rid of any side effects for example avoiding the negative number in list.

Refer the below complete code and its output.



object ScalaExample {

  //Partial function: MUltiply the input by 100 and return it.
  val multiplyBy100: PartialFunction[Int, Int] = {
    case x if x > 0 => x * 100
  }

  def main(args: Array[String]): Unit = {

    //List of numbers
    val numbers1 = List(1, 4, 5, 6, 7)
    //Use the partial function and coll
    println("numbers1::" + (numbers1 collect multiplyBy100))

    //List contains negative numbers as well
    val numbers2 = List(-1, -2, -3, 10)
    println("numbers2::" + (numbers2 collect multiplyBy100))

  }
}



numbers1::List(100, 400, 500, 600, 700)
numbers2::List(1000)


Scala’s PartialFunction trait contains the isDefinedAt method which can be called to check whether it handles the given value.

For example, We can call like this multiplyBy100.isDefinedAt(-1) which returns false. whereas this one multiplyBy100.isDefinedAt(1) returns true.

Advertisements

Scala Companion Object

A companion object in scala is an object that’s declared in the same file as a class and has the same name as class. So we can create an instance of class without new keyword.

In this post, we are going to see how we can use Scala companion object with an example.

Refer the below code, we define the case class Book and the corresponding companion object with two apply methods to provide multiple constructors for “Book” case class and the “apply” methods provide default values for the unavailable fields.

Refer the main method of MainScala object where we create an instance Book class without new keyword and the companion object apply method would be called by that time.



object MainScala {

  def main(args: Array[String]) = {

    val book1 = Book("title1", 100.0f, "author1")
    val book2 = Book("title2", 50.0f)
    println("book1: " + book1)
    println("book2: " + book2)
  }
}

case class Book(title: String, price: Float, author: String, publisher: String)

object Book {

  def apply(title: String, price: Float, author: String): Book = {

    val book = new Book(title, price, author, "")
    book
  }

  def apply(title: String, price: Float): Book = {

    val book = new Book(title, price, "", "")
    book
  }
}


The output of the above example is given below


book1: Book(title1,100.0,author1,)
book2: Book(title2,50.0,,)

SPECIAL CASE PATTERN (Fowler)

Most of the time, we would throw an exception to handle an unexpected behavior. In some cases, if the caller code does not want to handle that error and follow a default approach, then we can use “Special Case Pattern”. Refer the below example to know how to do that.

Assume that we have class “BillingDao” contains methods to fetch the billing details of an employee. “getBillingDetails” is a method returns the billing details of an employee by his/her company name. Assume that if it does not find the billing details, then it will throw “BillingDetailsNotFoundException “. So the client code has to handle that scenario. We can refactor this code with “Special Case Pattern”


float rate = 0.0f
try {
  BillingDetails billingDetails= billingRateDao.getBillingDetails(employee.getCompany());
  rate+= billingDetails.getRate();
} catch(BillingDetailsNotFoundException e) {
  rate += getDefaultBillingRate()
}

We will create a new class “DefaultBillingDetails” which implements “BillingDetails” and we can specify the default billing details in it.
Then we can update the “BillingRateDAO” to return the instance of DefaultBillingDetails instead of throwing an exception. I have not given the BillingRateDAO code here but assume that it return an instance of DefaultBillingDetails.

The modified code will look like below.


BillingDetails billingDetails= billingRateDao.getBillingDetails(employee.getCompany());
  rate+= billingDetails.getRate();
....
.....
public class DefaultBillingDetails implements BillingDetails {
 public int getRate() {
 // return the per default rate
 }
}

Java 8: Stream sorted

In this post, we are going to see how we can use Stream.sorted method to sort a collection with an example.

Consider that we have Person class contains “name” and “age” fields and want to sort the list of person objects by age and then by name.

Refer the below code to know how to do that.


import com.google.common.collect.Lists;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class CollectionMain {

    static class Person {
        String name;
        Integer age;

        Person(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return new ToStringBuilder(this, ToStringStyle.SIMPLE_STYLE)
                .append("name", name)
                .append("age", age)
                .toString();
        }

        public String getName() {
            return name;
        }


        public Integer getAge() {
            return age;
        }

    }

    private static final Comparator PERSON_COMPARATOR = Comparator.comparing(Person::getAge).thenComparing(Person::getName);

    public static void main(String[] args) {
        List persons = Lists.newArrayList(new Person("John", 32),
            new Person("Tom", 33),
            new Person("Brad", 35),
            new Person("Varma", 38),
            new Person("Andy", 33));

        System.out.println(persons
            .stream()
            .filter(p -> p.age > 32)
            .sorted(PERSON_COMPARATOR)
            .collect(Collectors.toList()));

    }
}



[Andy,33, Tom,33, Brad,35, Varma,38]