Showing posts with label Core Java. Show all posts

Java 8 introduced default and static methods in interfaces. These features allow us to add new functionality in the interfaces without breaking the existing contract for implementing classes.

How do we define default and static methods?

Default method has default and static method has static keyword in the method signature.

public interface InterfaceA {
  double someMethodA();

  default double someDefaultMethodB() {
    // some default implementation
  }
  
  static void someStaticMethodC() {
    //helper method implementation 
  }

Few important points for default method

  • You can inherit the default method.
  • You can redeclare the default method essentially making it abstract.
  • You can redefine the default method (equivalent to overriding).

Why do we need default and static methods?

Consider an existing Expression interface with existing implementation like ConstantExpression, BinaryExpression, DivisionExpression and so on. Now, you want to add new functionality of returning the signum of the evaluated result and/or want to get the signum after evaluating the expression. This can be done with default and static methods without breaking any functionality as follows.

public interface Expression {
  double evaluate();

  default double signum() {
    return signum(evaluate());
  }

  static double signum(double value) {
    return Math.signum(value);
  }
}

You can find the full code on Github.

Default methods and multiple inheritance ambiguity problem

Java support multiple inheritance of interfaces. Consider you have two interfaces InterfaceA and InterfaceB with same default method and your class implements both the interfaces.

interface InterfaceA {
  void performA();
  default void doSomeWork() {
  
  }
}

interface InterfaceB {
  void performB();

  default void doSomeWork() {
 
  }
}

class ConcreteC implements InterfaceA, InterfaceB {

}

The above code will fail to compile with error: unrelated defaults for doSomeWork() from InterfaceA and InterfaceB.

To overcome this problem, you need to override the default method.

class ConcreteC implements InterfaceA, InterfaceB {
  override
  public void doSomeWork() {

  }
}
If you don't want to provide implementation of overridden default method but want to reuse one. That is also possible with following syntax.
class ConcreteC implements InterfaceA, InterfaceB {
  override
  public void doSomeWork() {
    InterfaceB.super.doSomeWork();
  }
}

I hope you find this post informative and useful. Comments are welcome!!!.

This is an introduction series to Apache Ignite. We will discuss about Apache Ignite, its features, usage as in-memory data grid, compute grid, distributed caching, near real-time caching and persistence distributed database.

What is Ignite?

  • It is in-memory compute platform.
  • It is in-memory data grid.
  • Durable, strongly consistent and highly available.
  • Providing option to run SQL like queries on cache (Providing JDBC API to support this).

Durable memory

Apache Ignite is memory-centric platform based on durable memory architecture. It allows you to store and processing data on in-memory(RAM) and on disk (If Ignite Native persistence is enabled). When the Ignite native persistence is enabled, it will treat disk as superset of data, which is cable of surviving crash and restarts.

In-memory features

RAM is always treated as first memory tier, all the processing happens there. It has following characteristics.

  • Off-heap based: All the data and indexes are stored outside of Java heap which helps in processing petabytes of data.
  • Since all data and indexes are off-heap based, it removes noticeable GC pauses since application code is only source possible for pause-the-world events.
  • It has predictable memory usage. You can configure memory usage with MemoryConfiguration
  • It uses memory as efficient as possible and runs defragmentation routines in the background.
  • Data and indexes on disk and in-memory are stored as same page format which improved the performance and avoids unnecessary data format conversion.

Persistence features

Here are few high-level persistence features.

  • Persistence is optional to disk. You can enable or disable it.
  • It provides data resiliency. If persistence is enabled, full dataset will be stored on physical disk and you can survives cluster restarts, crashes.
  • It can execute SQL queries on full dataset.
  • Cluster restarts are instantaneous. In-memory data will be cached automatically.

This article is in continuation to my other posts on Functional Interfaces, static and default methods and Lambda expressions.

Method references are the special form of Lambda expression. When your lambda expression are doing nothing other than invoking existing behaviour (method), you can achieve same by referring it by name.

  • :: is used to refer to a method.
  • Method type arguments are infered by JRE at runtime from context it is defined.

Types of method references

  • Static method reference
  • Instance method reference of particular object
  • Instance method reference of an arbitrary object of particular type
  • Constructor reference

Static method reference

When you refer static method of Containing class. e.g. ClassName::someStaticMethodName

class MethodReferenceExample {
  public static int compareByAge(Employee first, Employee second) {
    return Integer.compare(first.age, second.age);
  }
}

Comparator compareByAge = MethodReferenceExample::compareByAge;

Instance method reference of particular object

When you refer to the instance method of particular object e.g. containingObjectReference::someInstanceMethodName

static class MyComparator {
  public int compareByFirstName(User first, User second) {
    return first.getFirstName().compareTo(second.getFirstName());
  }
  
  public int compareByLastName(User first, User second) {
    return first.getLastName().compareTo(second.getLastName());
}

private static void instanceMethodReference() {
  System.err.println("Instance method reference");
  List<User> users = Arrays.asList(new User("Gaurav", "Mazra"),
      new User("Arnav", "Singh"), new User("Daniel", "Verma"));
  MyComparator comparator = new MyComparator();
  System.out.println(users);
  Collections.sort(users, comparator::compareByFirstName);
  System.out.println(users);
}

Instance method reference of an arbitrary object of particular type

When you refer to instance method of some class with ClassName. e.g. ClassName::someInstanceMethod;

Comparator<String> stringIgnoreCase = String::compareToIgnoreCase;
//this is equivalent to
Comparator<String> stringComparator = (first, second) -> first.compareToIgnoreCase(second);

Constructor reference

When you refer to constructor of some class in lambda. e.g. ClassName::new

Function<String, Job> jobCreator = Job::new;
//the above function is equivalent to
Function<String, Job> jobCreator2 = (jobName) -> return new Job(jobName);

You can find the full example on github.

You can also view my other article on Java 8

In this post, we will cover following topics.

  • What are Lambda expressions?
  • Syntax for Lambda expression.
  • How to define no parameter Lambda expression?
  • How to define single/ multi parameter Lambda expression?
  • How to return value from Lambda expression?
  • Accessing local variables in Lambda expression.
  • Target typing in Lambda expression.

What are Lambda expressions?

Lambda expressions are the first step of Java towards functional programming. Lambda expressions enable us to treat functionality as method arguments, express instances of single-method classes more compactly.

Syntax for Lambda expression

Lambda has three parts:

  • comma separated list of formal parameters enclosed in parenthesis.
  • arrow token ->.
  • and, body of expression (which may or may not return value).

(param) -> { System.out.println(param); }
Lambda expression can only be used where the type they are matched are functional interfaces.

How to define no parameter Lambda expression?

If the lambda expression is matching against no parameter method, it can be written as:

() -> System.out.println("No paramter expression");

How to define single/ multi parameter Lambda expression?

If lambda expression is matching against method which take one or more parameter, it can be written as:

(param) -> System.out.println("Single param expression: " + param);

(paramX, paramY) -> System.out.println("Two param expression: " + paramX + ", " + paramX);

You can also define the type of parameter in Lambda expression.

(Employee e) -> System.out.println(e);

How to return value from Lambda expression?

You can return value from lambda just like a method did.

(param) -> {
  // perform some steps
  return "some value";
};

In case lambda is performing single step and returning value. Then you can write it as:

//either
(int a, int b) -> return Integer.compare(a, b);

// or simply lambda will automatically figure to return this value
(int a, int b) -> Integer.compare(a, b);

Accessing local variables in Lambda expression

Lambda can access the final or effectively final variables of the method in which they are defined. They can also access the instance variables of enclosing class.

Target typing in Lambda expression

You might have seen in earlier code snippets that we have omitted the type of parameter, return value and the type of Lambda. Java compiler determines the target type from the context lambda is defined.

Compiler checks three things:

  • Is the target type functional interface?
  • Is list of parameter and its type matched with the single method?
  • Does the return type matched with the single method return type?

Now, Let's jump to an example to verify it.

@FunctionalInterface
interface InterfaceA {
  void doWork();
}

@FunctionalInterface
interface InterfaceB<T> {
  T doWork();
}

class LambdaTypeCheck {
  
  public static void main (String[] args) {
    LambdaTypeCheck typeCheck = new LambdaTypeCheck();
    typeCheck.invoke(() -> "I am done with you");
  }
  
  public <T> T invoke (InterfaceB<T> task) {
    return task.doWork();
  }

  public void invoke (InterfaceA task) {
    task.doWork();
  }
}
When you call typeCheck.invoke(() -> "I am done with you"); then invoke(InterfaceB<T> task) will be called. Because the lambda return value which is matched by InterfaceB<T>.

Java 8 reincarnated SAM interfaces and termed them Functional interfaces. Functional interfaces have single abstract method and are eligible to be represented with Lambda expression. @FunctionalInterface annotation is introduced in Java 8 to mark an interface as functional. It ensures at compile-time that it has only single abstract method, otherwise it will throw compilation error.

Let's define a functional interface.

@FunctionalInterface
public interface Spec<T> {
  boolean isSatisfiedBy(T t);
}

Functional interfaces can have default and static methods in them and still remains functional interface.

@FunctionalInterface
public interface Spec<T> {
  boolean isSatisfiedBy(T t);
 
  default Spec<T> not() {
    return (t) -> !isSatisfiedBy(t);
  }
 
  default Spec<T> and(Spec<T> other) {
    return (t) -> isSatisfiedBy(t) && other.isSatisfiedBy(t);
  }
 
  default Spec<T> or(Spec<T> other) {
    return (t) -> isSatisfiedBy(t) || other.isSatisfiedBy(t);
  }
}
If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.

In this post, we will cover following items.

  • What is java.util.function.Predicate?
  • How to filter data with Predicates?
  • Predicate chaining.

Java 8 introduced many new features like Streaming API, Lambdas, Functional interfaces, default methods in interfaces and many more.

Today, we will discuss about Predicate interface added in java.util.function package and its usage in filtering in-memory data.

What is java.util.function.Predicate?

Predicate is like a condition checker, which accepts one argument of type T and return the boolean value.

It's a functional interface with functional method test(Object). Here, Object is typed.

@FunctionalInterface
interface Predicate<T> {
  public boolean test(T t);
}

How we can filter data with Predicates?

Consider we have Collection of employees and we want to filter them based on age, sex, salary and/ or with any other combinations. We can do that with Predicate.

Let's understand this with one short example.

class Employee {
  private long id;
  private String firstName;
  private String lastName;
  private int age;
  private Sex sex;
  private int salary;

  // getters, constructor, hashCode, equals, to String
}

Defining predicates for filtering

Predicate<Employee> male = e -> e.getSex() == Sex.MALE;
Predicate<Employee> female = e -> e.getSex() == Sex.FEMALE;
Predicate<Employee> ageLessThan30 = e -> e.getAge() < 30;
Predicate<Employee> salaryLessThan20 = e -> e.getSalary() < 20000;
Predicate<Employee> salaryGreaterThan25 = e -> e.getSalary() > 25000;

Filtering employees with Predicates

employees.stream().filter(male).collect(Collectors.toList());
employees.stream().filter(female).collect(Collectors.toList());
employees.stream().filter(ageLessThan30).collect(Collectors.toList());
employees.stream().filter(salaryLessThan20).collect(Collectors.toList());

Here, employees reference is of type java.util.List.

Collections framework is retrofitted for Streaming API and have stream() and parallelStream() methods along with few other additions.filter() method is defined in Stream. We are streaming employees collection and filtering them based on the Predicate and then collecting as java.util.List.

Predicate chaining

java.util.function.Predicate have three default method. Two of them and(Predicate<T> other) and or(Predicate<T> other) is used for predicate chaining.

Filtering employees with multiple predicates

Let's say, we want to filter collection of employees which involves multiple conditions like

  • all male salary less than 20k.
  • all female salary greater than 25k.
  • all male salary either less than 20 k or greater than 25k.

Let's understand this with quick example.

Defining predicates

Predicate<Employee> male = e -> e.getSex() == Sex.MALE;
Predicate<Employee> female = e -> e.getSex() == Sex.FEMALE;
Predicate<Employee> ageLessThan30 = e -> e.getAge() < 30;
Predicate<Employee> salaryLessThan20 = e -> e.getSalary() < 20000;
Predicate<Employee> salaryGreaterThan25 = e -> e.getSalary() > 25000;
Predicate<Employee> salaryLessThan20OrGreateThan25 = salaryLessThan20.or(salaryGreaterThan25);

Predicate<Employee> allMaleSalaryLessThan20 = male.and(salaryLessThan20);
Predicate<Employee> allMaleAgeLessThan30 = male.and(ageLessThan30);
Predicate<Employee> allFemaleSalaryGreaterThan25 = female.and(salaryGreaterThan25);

Predicate<Employee> allMaleSalaryLessThan20OrGreateThan25 = male.and(salaryLessThan20OrGreateThan25);

Line 1 => Predicate test for employee male

Line 2 => Predicate test for employee female

Line 3 => Predicate test for employee age less than 30

Line 4 => Pedicate test for employee salary less than 20000

Line 8 => Predicate test for employee male and salary less than 20000

Line 10 => Predicate test for employee female and salary greater than 25000

Line 12 => Predicate test for employee male and salary either less than 20000 or greater than 25000

Filtering employees with predicate chaining

employees.stream().filter(allMaleSalaryLessThan20).collect(Collectors.toList());
employees.stream().filter(allMaleAgeLessThan30).collect(Collectors.toList());
employees.stream().filter(allFemaleSalaryGreaterThan25).collect(Collectors.toList());
employees.stream().filter(allMaleSalaryLessThan20OrGreateThan25).collect(Collectors.toList());

This is how we can use Predicate to filter in-memory data. I hope you find this post informative and helpful. You can get the full example code on Github.