Java Short-Circuit Evaluation | Java Operators

There are so many operators available in Java. Here we will discuss Java Short circuit operators and how they evaluate the given expression. As a Java developer, you must know these basics and how to use them effectively.

OperatorEvaluation
&& and ||Short-Circuit
& and |Full

Operator && and || are known as short-circuit operators and how they evaluate an expression is known as short circuit evaluation.

What exactly Short-circuit evaluation is?

The short circuit evaluation enables you to not evaluate the right-hand side AND or OR expression when the overall result of the expression can be predicted from the left-hand side value.

So for AND (&&), both parts must be true for the overall results to be true. For OR (||), one part must be true, either one of these. The other may be false, it doesn’t matter. The overall result will be true. And for exclusive OR (^), either part has to be true, and the other part has to be false for the overall result to become true.

Now, instead of the double ampersand (&&) and double vertical line (||), there are also single ampersand and single vertical line operators available, and they’re known as full evaluation versus the double ampersand and double vertical line, which are known as short circuit evaluation.

Refer to the below picture and see how the evaluation of these operators happens.

Java Short-Circuit Evaluation

Example

Now let’s understand this using the below code snippet.

 
int a = 3, b = 2;
boolean c = false;

c = (a > b && ++b == 3); 
System.out.println("value of c is "+c + " and b is "+b);

c = (a > b && ++b == 3);
System.out.println("value of c is "+c + " and b is "+b);

c = (a > b || ++b == 3); 
System.out.println("value of c is "+c + " and b is "+b);

c = (a < b || ++b == 3); 
System.out.println("value of c is "+c + " and b is "+b);

c = (a < b | ++b == 3); 
System.out.println("value of c is "+c + " and b is "+b);

c = (a > b & ++b == 3);
System.out.println("value of c is "+c + " and b is "+b);

c = (a < b ^ ++b == 3);
System.out.println("value of c is "+c + " and b is "+b);

c = (a > b ^ ++b == 3);
System.out.println("value of c is "+c + " and b is "+b);

//Output
value of c is true and b is 3
value of c is false and b is 3
value of c is false and b is 4
value of c is true and b is 4
value of c is true and b is 5
value of c is false and b is 6
value of c is true and b is 7
value of c is false and b is 8

Note: You don’t have to put round brackets around Booleans, but that may make your code a little bit more readable, just sort of from a visual point of view so the Boolean expression will stand out.

Output Explantion

Let’s understand the output of each line.

 c = (a > b && ++b == 3); 

For AND condition, both parts of the expression need to be true for the overall results to become true. So we have to evaluate both parts to tell that.

If you look at a Boolean expression, the double ampersand is AND, the first part evaluates to true and then ++b increment the b to 3 and it also evaluates to true. That’s why c is true and b is 3.

See the next line of code which is a copy of the first line but its output is different from the first line. In this case, the first condition evaluates to false as b is incremented to 3 in the first line. Hence the second part of the expression will not be evaluated.

 c = (a > b || ++b == 3);  

OR condition, here one part of the expression needs to be true for the overall results to become true. So we have to evaluate both parts to tell that.

If you look at a Boolean expression, the first part evaluates to false and then ++b increment the b to 4 and it also evaluates to false. That’s why c is false and b is 4.

The next line also used the OR operator but changed the first part of the condition to a < b.

 c = (a < b || ++b == 3);  

In this case the first part evaluates to true hence the second part of the expression is omitted from the evaluation. That’s why c is true and b is still 4.

The next line also used the OR operator but not the short circuit one. This time we used the full evaluation of OR (|) means a single vertical line. The difference in full evaluation is even if the first condition of the OR is true the second part will still be evaluated and it doesn’t impact the overall result of the expression.

 c = (a < b | ++b == 3);  

Hence, in the output of the above line value of c is true and b is incremented to 5.

The next line is having the full evaluation AND operator. These means don’t matter the first condition evaluates to true or false the second condition will be evaluated which is not the case when we use short circuit AND (&&) operator.

 c = (a > b & ++b == 3);  

In the above line the first condition is evaluated to false but still, the second condition is evaluated which is not the case when we use &&. Hence The value of c is false in the output of the above line but the b is still incremented to 6.

The next two lines of the code are using XOR (^) operator. This is also used for a full evaluation of both the expression. This will return true if one condition is true and another is false.

 c = (a < b ^ ++b == 3);  

Here the first condition is evaluated to true then it increments b to 7 and the second condition evaluates to false.

 c = (a > b ^ ++b == 3);  

The last line output value of c is false and b is 8. Here if you see the first condition is evaluated to false then it incremented b to 8 and that condition is false.

Conclusion

Here we discussed the &&, ||, &, | and ^ operators and how they evaluate a given condition. While using full evaluation the second part of the condition is evaluated doesn’t matter the first condition is evaluated to true or false.

Happy Learning !!

Read more

Refrence

Understanding and preventing memory leaks in Java

For any developer, memory should be one of the most precious resources to think of while writing a program. A program can be said to be memory efficient when it consumes as little memory as possible when in operation but still doing what it was designed to do. So, before write code think of memory uses, do you know What happens when a Java object is created?

What is a Memory Leak?

In simple words, memory leak means unused memory that the garbage collectors can not reclaim.

A memory leak occurs when objects are no longer being used by the application, but the garbage collector is unable to clear them from working memory. This is a serious problem because these objects hold the memory that could otherwise be used by other parts of the program. With time, this piles up and leads to a degradation in system performance over time.

Garbage Collection in Java

One of the coolest features of Java is its automatic memory management. The Garbage Collection is a program that implicitly takes care of memory allocation and deallocation. It’s an effective program and can handle the majority of memory leaks that are likely to occur. However, it’s not infallible. Memory leaks can still sneak up and start taking up precious resources and, in worst cases, result in the java.lang.OutOfMemoryError.

It’s worth mentioning that an OutOfMemoryError is not always because of memory leaks. At times, it could be poor code practices like loading large files in memory.

The three common causes of memory leaks?

  • Misused static fields
  • Un closed streams
  • Un closed connections

Misused static fields

Static fields live in the memory as long as the class that owns them is loaded in the JVM, which means there are no instances of the class in the JVM, at this point, the class will be unloaded and the static field will be marked for garbage collection. But the catch here is, the static classes can live in the memory forever.

Consider the following code:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class StaticDemo {
public static List&lt;Integer&gt; list = new ArrayList&lt;&gt;();

public void populateList() {
for (int i = 0; i &lt; 10000000; i++) {
   list.add(new Random().nextInt());
}
}
public static void main(String[] args) {
  new StaticDemo().populateList();
}
}

This is a simple and small code snippet, we have a static List and we added values into it. But If we see the declaration of the list we have used static in front of it.  That’s the problem, the memory occupied by this list will be in use until the program finishes its execution even though the operations on the list are already completed.

To avoid this mistake, Minimize the use of static fields in your application.

Un closed streams

Till now we have understood memory leak is when code holds a reference to an object and the garbage collector can’t claim that object. But, a closed stream object is not memory unless it holds a reference of an unclosed stream.

Usually, the operating system limits how many open files (while using FileInputStream) an application can have. So, if such streams are not closed and the garbage collector may take some to claim these objects, it is also a case of the leak but not particularly a memory leak.

Refer to the following code snippet:

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

public class OpenStreamDemo {

    public static void main(String[] args) throws IOException {
        URL url = new URL("http://ergast.com/api/f1/2004/1/results.json");
        ReadableByteChannel rbc = Channels.newChannel(url.openStream());
        FileOutputStream outputStream = new FileOutputStream("/");
        outputStream.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
    }
}

Here the unclosed FileOutputStream and ReadableByteChannel will cause potential issues. The solution to this problem would be closing these stream objects once they are used and not require further. Or use java to try with resources wherever allowed.

rbc.close();
outputStream.close();

Un closed connections

The frequent mistake in Java programming is, developer forgot to close the database connections.  Having an unclosed database connection can give you a tough time in production and they are difficult to replicate in local environments.

Refer to the below code snippet:

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class OpenConnectionDemo {

    public static void main(String[] args) {
        try {
            List&lt;String&gt; names = fetchUsersName("foo", "bar");
            names.forEach(System.out::println);

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static List&lt;String&gt; fetchUsersName(String username, String password) throws SQLException {
        List&lt;String&gt; names = new ArrayList&lt;&gt;();
        Connection con = DriverManager.getConnection("jdbc:myDriver:devDB",
                username,
                password);

        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT first_name, last_name FROM users");

        String firstName = "";
        String lastName = "";

        while (rs.next()) {
            firstName = rs.getString("first_name");
            lastName = rs.getString("last_name");
            names.add(firstName + " " + lastName);
        }
        return names;
    }
}

Here every resource is leaking. Here we could have use try-catch and finally, and inside the finally block we can close

stmt.close();
con.close();

Here is the complete code for the fetchUsersName method.

public static List&lt;String&gt; fetchUsersName(String username, String password) throws SQLException {
    Statement stmt = null;
    Connection con = null;
    List&lt;String&gt; names = new ArrayList&lt;&gt;();
    try {

        con = DriverManager.getConnection("jdbc:myDriver:devDB",
                username,
                password);

        stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT first_name, last_name FROM users");

        String firstName = "";
        String lastName = "";

        while (rs.next()) {
            firstName = rs.getString("first_name");
            lastName = rs.getString("last_name");
            names.add(firstName + " " + lastName);
        }
    }catch (SQLException se){
        se.printStackTrace();
    }finally {
        stmt.close();
        con.close();
    }
    return names;
}

Or we can use try with resources like below.

public static List&lt;String&gt; fetchUsersName(String username, String password) throws SQLException {
    List&lt;String&gt; names = new ArrayList&lt;&gt;();
    try (Connection con = DriverManager.getConnection("jdbc:myDriver:devDB",username,password);
         Statement stmt = con.createStatement();
    ){
        ResultSet rs = stmt.executeQuery("SELECT first_name, last_name FROM users");

        String firstName = "";
        String lastName = "";

        while (rs.next()) {
            firstName = rs.getString("first_name");
            lastName = rs.getString("last_name");
            names.add(firstName + " " + lastName);
        }
    }catch (SQLException se){
        se.printStackTrace();
    }
    return names;
}

We can also use ORM like hibernate or jooq which provides easier and more maintainable resource handling.

So the take away from this post are:

  1. Be careful while using static fields.
  2. Make sure to close the stream and connection or use try with resources.
  3. Use ORM if your application allows.

 

Happy Learning !!!

Java 8 Stream API with examples

What is the stream?

Java Stream API

Streams are wrappers around a data source, which allows us to operate with that data source and making bulk processing convenient and fast. A stream represents a sequence of objects from a source, which supports aggregate operations.

The following are the characteristics of a Stream:

The sequence of elements: A stream provides a set of elements of a specific type in a sequential manner. A stream gets/computes elements on demand. It never stores the elements.

Source: Stream takes Collections, Arrays, or I/O resources as an input source.

Aggregate operations: Stream supports aggregate operations like filter, map, limit, reduce, find, match, and so on.

Pipelining: Most of the stream operations return stream itself so that their result can be pipelined. These operations are called intermediate operations and their function is to take input, process them, and return output to the target. collect() method is a terminal operation that is normally present at the end of the pipelining operation to mark the end of the stream.

Automatic iterations: Stream operations do the iterations internally over the source elements provided, in contrast to Collections where explicit iteration is required.

Let’s see a few ways to obtain a stream:

    1. Using existing Array
int [] arr = new int[] {1,2,3,4,5,6,7,8,9,10};
		
Stream.of(arr);

    1. Using existing Collection
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

System.out.println("List Stream\n");
list.stream().forEach(System.out::println);

Set<Integer> set = new HashSet<>(list);

System.out.println("\nSet Stream\n");		
set.stream().forEach(System.out::println);

Map<Integer, String> map = new HashMap<>();

map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

System.out.println("\nMap Stream\n");
map.entrySet().stream().forEach(System.out::println);

    1. Stream from individual objects using Stream.of()
Stream.of(1,2,3,4,5,6);
    1. Using Stream.builder()
Stream.Builder<String> builder = Stream.builder();
builder.accept("welcome");
builder.accept("to");
builder.accept("Java");
builder.accept("8");

Stream<String> stream = builder.build();

stream.forEach(System.out::println);

Stream Operations: Now let’s try some common usages and operations we can perform on and with the help of stream API.

forEach:

forEach() is the simplest and most common operation, it loops over the stream elements, calling the supplied function on each element. You can refer to the above code block to see the uses of foreach(). This method is so common that is has been added directly in Iterable, Map, etc. Observe the following code snippet.

import java.util.Arrays;
import java.util.List;

public class StreamDemo {

	public static void main(String[] args) {
		List<String> cities = Arrays.asList("Delhi","Mumbai","New York","London");
		
		System.out.println("===== Conventional way of looping the list =====");
		for(int i =0 ; i< cities.size() ; i++){
			System.out.println(cities.get(i));
		}
		
		System.out.println("===== Using for each loop =====");
		for(String str : cities){
			System.out.println(str);
		}
		
		System.out.println("===== Using stream and method reference =====");
		cities.stream().forEach(System.out::println);
		
		System.out.println("===== Using stream and lambda =====");
		cities.stream().forEach(city ->{
			System.out.println(city);
		});
	}
}

Once you execute this the output will as below:

===== Conventional way of looping the list =====
Delhi
Mumbai
New York
London
===== Using for each loop =====
Delhi
Mumbai
New York
London
===== Using stream and method reference =====
Delhi
Mumbai
New York
London
===== Using stream and lambda =====
Delhi
Mumbai
New York
London

Similar to forEach() we can also use a stream to perform many more tasks. Like filtering the data, getting count, finding distinct elements, replacing items with mapping new values, etc. Observe the below code snippet, where we are filtering the cities starting with ‘D’ from the city list.

List<String> cities = Arrays.asList("Delhi","Mumbai","New York","London","Dublin");
		
List<String> startingWithD = cities.stream().filter(c -> c.startsWith("D")).collect(Collectors.toList());
		
System.out.println("City name start with d "+startingWithD);

// Output:
City name start with d [Delhi, Dublin]

Recommended Read:

Java 8 method reference with example
Java 8 Predicates
Java 8 forEach method in Iterable Interface
Java 8 forEach method in Iterable Interface
Java 8 Default and Static method in Interface
Java 8 – Comparison with Lambda

References:

Java 8 Stream

Java 8 – Comparison with Lambda

Before Java 8 sorting of a collection of custom, classes require a lot of code to define the sorting strategy using one of the interfaces provided in Java. We can either use java.lang.Comparable or java.util.Comparator. But since the inception of Java-8, we can reduce the lines of code using a lambda expression.

Lambda expression

In this tutorial, we will look at Java 8 Lambda support specifically at how to use it to write the Comparator and sorting of a Collection.

Let’s start it by creating an entity class we will be using in our example.

public class Employee {

	private int empId;

	private String name;

	private String department;

	private int age;

	public Employee() {

	}

	public Employee(int empId, String name, String department, int age) {
		super();
		this.empId = empId;
		this.name = name;
		this.department = department;
		this.age = age;
	}

	public int getEmpId() {
		return empId;
	}

	public void setEmpId(int empId) {
		this.empId = empId;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDepartment() {
		return department;
	}

	public void setDepartment(String department) {
		this.department = department;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Employee [empId=" + empId + ", name=" + name + ", department=" + department + ", age=" + age + "]";
	}

}

Till Java-7 if we have to sort a collection of Employee class mentioned above-using java.util.Comparator, we can achieve it in the following ways.

1. Using an anonymous class:

static void sortingListTheOldWay(){
	Collections.sort(employeeList,new Comparator<Employee>() {

		@Override
		public int compare(Employee e1, Employee e2) {
			
			return e1.getEmpId() - e2.getEmpId();
		}
		
	}); 
	
}

2. Using a Separator class:

class EmployeeDepartmentComparator implements Comparator<Employee>{

	@Override
	public int compare(Employee o1, Employee o2) {
		return o1.getDepartment().compareTo(o2.getDepartment());
	}
}

But after the arrival of Java-8, we can rewrite the first way like below using Lambda.

static void sortingUsingLambdaOneWay(){
	employeeList.sort((Employee e1,Employee e2) -> e1.getEmpId()-e2.getEmpId());
}

To make the above code simpler we can simplify the above expression by excluding the type definition. The compiler is capable of inferring these types of definitions on its own.

static void sortingUsingLambdaAnotherWay(){
	employeeList.sort((e1, e2) -> e1.getEmpId()-e2.getEmpId());
}

We can even sort a collection by defining a static method and then using the Static method reference. Refer the following code snippet.

static int compareByAge(Employee e1, Employee e2){
    return e1.getAge() - e2.getAge();
}

static void sortingUsingLambdaUsingStaticMethodReference(){
	employeeList.sort(ComparatorUsingLambda::compareByAge);
}

Refer the below complete code and uncomment the method call in main method one by to see the output of each method.

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ComparatorUsingLambda {

	static List<Employee> employeeList;
	
	public static void main(String[] args) {
		
		loadData();
		
		System.out.println("Employee List before sorting "+employeeList);
		
		sortingListTheOldWay();
		//sortingUsingCustomComparatorClass();
		//sortingUsingLambdaOneWay();
		//sortingUsingLambdaSecondWay();
		//sortingUsingLambdaUsingStaticMethodReference();
		System.out.println("Employee List after sorting "+employeeList);
	}
	
	static void sortingListTheOldWay(){
		Collections.sort(employeeList,new Comparator<Employee>() {

			@Override
			public int compare(Employee e1, Employee e2) {
				
				return e1.getEmpId() - e2.getEmpId();
			}
			
		}); 
	}
	
	static void sortingUsingCustomComparatorClass(){
		Collections.sort(employeeList,new EmployeeDepartmentComparator());
	}

	static void sortingUsingLambdaOneWay(){
		employeeList.sort((Employee e1,Employee e2) -> e1.getEmpId()-e2.getEmpId());
	}
	
	static void sortingUsingLambdaSecondWay(){
		employeeList.sort((e1, e2) -> e1.getEmpId()-e2.getEmpId());
	}
	
	static void sortingUsingLambdaUsingStaticMethodReference(){
		employeeList.sort(ComparatorUsingLambda::compareByAge);
	}
	
	static int compareByAge(Employee e1, Employee e2){
		
		return e1.getAge() - e2.getAge();
	}
	
	
	static void loadData(){
		employeeList = Arrays.asList(
			new Employee(10002, "Employee 1", "IT", 34),
			new Employee(10001, "Employee 2", "IT", 26),
			new Employee(10003, "Employee 3", "Admin", 56),
			new Employee(10005, "Employee 4", "Sales", 32),
			new Employee(10004, "Employee 5", "IT", 23)
		);
	}
	
}

class EmployeeDepartmentComparator implements Comparator<Employee>{

	@Override
	public int compare(Employee o1, Employee o2) {
		return o1.getDepartment().compareTo(o2.getDepartment());
	}
}

happy Learning !!

How to make a Java collection unmodifiable?

As array support, fixed-size data and the size has to be calculated during the array initialization programming languages invented collections to overcome the limitation of the array. But as the use of collections increases the requirements also changed. i.e. A collection that has been created should not allow any modification to it. This is the need, which introduced the concept of unmodifiable collections.

Convenience static factory methods on the List, Set, and Map interfaces let you easily create unmodifiable lists, sets, and maps.

A collection is considered unmodifiable if elements cannot be added, removed, or replaced. After you create an unmodifiable instance of a collection, it holds the same data as long as a reference to it exists.

A modifiable collection must maintain bookkeeping data to support future modifications. This adds overhead to the data that is stored in the modifiable collection. An unmodifiable collection does not need this extra bookkeeping data. Because the collection never needs to be modified, the data contained in the collection can be packed much more densely. Unmodifiable collection instances generally consume much less memory than modifiable collection instances that contain the same data.

So when to use an unmodifiable collection?

Whether to use an unmodifiable collection or a modifiable collection depends on the data in the collection.
An unmodifiable collection provides space efficiency benefits and prevents the collection from accidentally being modified, which might cause the program to work incorrectly. An unmodifiable collection is recommended for the following cases:

  • Collections that are initialized from constants that are known when the program is written.
  • Collections that are initialized at the beginning of a program from data that is computed or is read from something such as a configuration file.

For a collection that holds data that is modified throughout the program, a modifiable collection is the best choice. Modifications are performed in-place so that incremental additions or deletions of data elements are quite inexpensive. If this were done with an unmodifiable collection, a complete copy would have to be made to add or remove a single element, which usually has unacceptable overhead.

Note: Making any change to the unmodifiable collection will cause “java.lang.UnsupportedOperationException”.

Let’s try an example to create an unmodifiable collection.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class UnModifiableCollection {

	public static void main(String[] args) {
		List<String> list = new ArrayList<>(Arrays.asList("Temp","Dist","Demt","bin","Hello")) ;
		
		System.out.println("print 1 "+list);
		
		list.add("check");
		
		System.out.println("print 2 "+list);
		
		list = Collections.unmodifiableList(list);
		
		list.add("set"); // This line will prompt the Exception

		// This also creates fixed-size list backed by an array.
	    List<String> unmodifiable = Arrays.asList("Temp","Dist","Demt","bin","Hello"); 
	     
	     // unmodifiable.add("3232"); // Even this line will also prompt the same Exception. Uncomment it to verify. 

	}
}

If you run the above program the output will be like:

print 1 [Temp, Dist, Demt, bin, Hello]
print 2 [Temp, Dist, Demt, bin, Hello, check]
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055)
	at UnModifiableCollection.main(UnModifiableCollection.java:21)

The java.util.Collections class offers the following methods to create unmodifiable collections.

List of methods provided by Collections class to create unmodifiable collection

From Java 11 onward we can create an unmodifiable collection using the Java Stream API.

The Streams library includes a set of terminal operations known as Collectors. A Collector is most often used to create a new collection that contains the elements of the stream. The java.util.stream.The collectors class has Collectors that create new unmodifiable collections from the elements of the streams.
If you want to guarantee that the returned collection is unmodifiable, you should use one of them toUnmodifiable- collectors. These collectors are:

Collectors.toUnmodifiableList()
Collectors.toUnmodifiableSet()
Collectors.toUnmodifiableMap(keyMapper, valueMapper)
Collectors.toUnmodifiableMap(keyMapper, valueMapper, mergeFunction)

Recommended Read

ArrayList vs LinkedList
Java 8 Default and Static method in Interface

Happy Learning !!

Java 8 Predicates with example

Like many other functional interfaces in Java 8, Java introduces a functional interface called Java Predicates. A functional interface is one that contains only one abstract method, for details read functional interface. Predicate represent (Boolean-valued function) which takes the only argument. It returns true if the input argument matches the predicate or false.

@FunctionalInterface
java.util.function. public interface Predicate

Functional Method:

boolean test(T t);

Evaluates this predicate on the given argument and return true if the input argument matches the predicate, otherwise false.

Default methods:

default Predicate and(Predicate other)

Returns a composed predicate that represents a short-circuiting logical AND of this predicate and another. When evaluating the composed predicate, if this predicate is false, then the other predicate is not evaluated.

Any exceptions thrown during evaluation of either predicate are relayed to the caller; if the evaluation of this predicate throws an exception, the other predicate will not be evaluated.

default Predicate or(Predicate other)

Returns a composed predicate that represents a short-circuiting logical OR of this predicate and another. When evaluating the composed predicate, if this predicate is true, then the other predicate is not evaluated.

Any exceptions thrown during evaluation of either predicate are relayed to the caller; if the evaluation of this predicate throws an exception, the other predicate will not be evaluated.

default Predicate negate()

Returns a predicate that represents the logical negation of this predicate.

Static method:

static Predicate isEqual(Object targetRef)

Returns a predicate that tests if two arguments are equal according to Objects.equals(Object, Object).

Example: Predicate to check empty string

import java.util.function.Predicate;

public class PredicateExample {

	 //predicate to check if a String is empty 
	static Predicate<String> isEmpty = new Predicate<String>() {
		
		@Override
		public boolean test(String t) {
			
			return (t == null || t.trim().isEmpty());
		}
	};  

	public static void main(String[] args) {
		
		System.out.println("Empty "+isEmpty.test("Java"));
		System.out.println("Empty "+isEmpty.test("Java "));
		System.out.println("Empty "+isEmpty.test(""));
		System.out.println("Empty "+isEmpty.test(" "));
		System.out.println("Empty "+isEmpty.test(null));
		
	}
}

The output will be:

Empty false
Empty false
Empty true
Empty true
Empty true

The isEmpty() predicate mentioned above can also be written as below using a lambda expression.

static Predicate<String> isEmptyString = s ->  (s == null || s.trim().isEmpty()); 

Let’s see a few more Predicate examples using its other methods.

and():

import java.util.function.Predicate;

public class PredicateExample {

	static Predicate<Integer> greaterThanZero = i -> i  > 0;
	
	static Predicate<Integer> lessThanHundred = i -> i  < 100;
	
	static Predicate<Integer> andPridicate = greaterThanZero.and(lessThanHundred);

	
	public static void main(String[] args) {
		System.out.println("Result "+andPridicate.test(10));
		System.out.println("Result "+andPridicate.test(99));
		System.out.println("Result "+andPridicate.test(101));
		System.out.println("Result "+andPridicate.test(-1));
	}
}

The output will be:

Result true
Result true
Result false
Result false

or() and negate() method: To see the uses of or () and negate() methods observe the below code snippet.

Let’s create a class named Employee.

public class Employee {

	private int empId;

	private String name;

	private String department;

	private int age;

	public Employee() {

	}

	public Employee(int empId, String name, String department, int age) {
		super();
		this.empId = empId;
		this.name = name;
		this.department = department;
		this.age = age;
	}

	public int getEmpId() {
		return empId;
	}

	public void setEmpId(int empId) {
		this.empId = empId;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDepartment() {
		return department;
	}

	public void setDepartment(String department) {
		this.department = department;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Employee [empId=" + empId + ", name=" + name + ", department=" + department + ", age=" + age + "]";
	}

}

Create another class to define predicates, in this class will define two predicates to filter the employees by age and by the department.

import java.util.function.Predicate;

public class EmployeePredicates {

	public static Predicate<Employee> ageAbove25(){
		return employee -> employee.getAge() >= 25;
	}
	
	public static Predicate<Employee> ofDepartent(String dept){
		return emp -> emp.getDepartment().equalsIgnoreCase(dept);
	}

}

Now let’s create a class to run the test for the above-mentioned predicates.

import java.util.Arrays;
import java.util.List;

public class PredicateExample {

public static void main(String[] args) {
		
		List<Employee> employees = createEmpData();
		
		// using negate ()
		// It return a logical negation of the predicate 
		System.out.println("negate start");
		employees.stream().filter(EmployeePredicates.ageAbove25().negate()).forEach(System.out::println);
		System.out.println("negate end");
		
		// using or ()
		// It returns a composed predicate that represents a short-circuiting logical
		// OR of this predicate and another.
		System.out.println("or start");
		employees.stream().filter(EmployeePredicates.ageAbove25()
				.or(EmployeePredicates.ofDepartent("Finance"))).forEach(System.out::println);
		System.out.println("or end");
			
	}
	
	static List<Employee> createEmpData(){
		return Arrays.asList(new Employee [] {
				new Employee(1001, "Tom", "IT", 26),
				new Employee(1002, "Ram", "IT", 28),
				new Employee(1003, "Shyam", "Finance", 21),
				new Employee(1003, "Jamal", "Finance", 23),
				new Employee(1004, "Aman", "Finance", 29),
				new Employee(2002, "Raghu", "Finance", 30),
				new Employee(2005, "john", "HR", 24),
				new Employee(3001, "Foo", "Test", 20),
				new Employee(3007, "bar", "Test", 23),
		});
	}

}

Output:

negate start
Employee [empId=1003, name=Shyam, department=Finance, age=21]
Employee [empId=1003, name=Jamal, department=Finance, age=23]
Employee [empId=2005, name=john, department=HR, age=24]
Employee [empId=3001, name=Foo, department=Test, age=20]
Employee [empId=3007, name=bar, department=Test, age=23]
negate end

or start
Employee [empId=1001, name=Tom, department=IT, age=26]
Employee [empId=1002, name=Ram, department=IT, age=28]
Employee [empId=1003, name=Shyam, department=Finance, age=21]
Employee [empId=1003, name=Jamal, department=Finance, age=23]
Employee [empId=1004, name=Aman, department=Finance, age=29]
Employee [empId=2002, name=Raghu, department=Finance, age=30]
or end

As described above the negate method will perform logical negation of the predicate hence returned all the employees having age less than 25.

Similarly, the or method will return a composed predicate that represents a logical OR between the given two predicates.

Reference:
Java Doc Predicate

Read about Java 8 forEach() method.

Happy Learning !!

Java 8 functional interface with example

We have already discussed, a lot of changes have been introduced in Java 8, like Default and static methods in interface, foreach method in Iterable Interface. Today we will discuss the java 8 functional interface and the annotation.

@FunctionalInterface

Functional interface

An interface with exactly one abstract method will be considered as a functional interface. The annotation @FunctionalInterface can be used to mark it as a functional interface. If an interface has only an abstract method then there is no need to even put the @FunctionalInterface annotation over it.

One of the major benefits of the functional interface is the possibility to use a lambda expression to instantiate them. We can instantiate them using an anonymous class but that code looks bulky.

Java 8 added a new Package java.util.function and the interfaces in this package are annotated with FunctionalInterface. Refer to the below description of the functional interface form Java doc.

Functional interfaces provide target types for lambda expressions and method references. Each functional interface has a single abstract method, called the functional method for that functional interface, to which the lambda expression’s parameter and return types are matched or adapted. Functional interfaces can provide a target type in multiple contexts, such as assignment context, method invocation, or cast context, like:

     // Assignment context
     Predicate<String> p = String::isEmpty;

     // Method invocation context
     stream.filter(e -> e.getSize() > 10)...

     // Cast context
     stream.map((ToIntFunction) e -> e.getSize())...

The Example of a functional interface is the Runnable interface. See the below implementation of the Runnable interface from Java source.

@FunctionalInterface
public interface Runnable {

    public abstract void run();

}

Let’s try to implement the Runnable interface with both anonymous class and with the lambda expression and see the difference.

Using Anonymous class

Thread t = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("The anonymous way");
			}
		});
		
		t.start();

Using Lambda expression

Runnable runnable = () ->{
		System.out.println("The lambda way");	
	};
	
	Thread t1 = new Thread(runnable);
	t1.start();

Let see some example of the valid functional interfaces:

(1) The best case will be interface with only one abstract method. Refer below example.

interface I1{
	
	int add(int a, int b);
}
public class MainTest {

	public static void main(String[] args) {

		I1 i = (a, b) -> {
			return a + b;
		};

		System.out.println(i.add(10, 20));
	}

}

// output will:- be the sum of a and b 30

(2) Interface with one abstract method and default method. Refer below example.

@FunctionalInterface
interface I2 {

	int add(int a, int b);
	
	default void display(){
		System.out.println("I am a functional interface");
	}
}

The interface I2 will be a valid functional interface even if you don’t put @FunctionalInterface annotation.

public class MainTest {

	public static void main(String[] args) {

		I2 i = (a, b) -> {
			return a + b;
		};
		int sum =  i.add(10, 20);
		System.out.println("the sum of a and b "+sum);
		
		i.display();
	}

}

/*
output will be:-
sum of a and b 30
I am a functional interface
*/

(3) Interface with one abstract method and with the default and static methods. Refer below example.

@FunctionalInterface
interface I3 {

	int add(int a, int b);
	
	default void display(){
		System.out.println("I am a functional interface");
	}
	
	static void foo(){
		System.out.println("I am a static method in a functional interface ");
	}
}

The interface I3 will be a valid functional interface even if you don’t put @FunctionalInterface annotation.

public class MainTest {

	public static void main(String[] args) {

		I3 i = (a, b) -> {
			return a + b;
		};
		int sum =  i.add(10, 20);
		System.out.println("sum of a and b "+sum);
		
		i.display();
		
		I3.foo();
	}

}

/* 
the output will be:-
the sum of a and b 30
I am a functional interface
I am a static method in a functional interface 
*/

Recommended Read

Java 8 Stream API with examples
Java 8 – Comparison with Lambda
Java 8 method reference with example

Happy Learning !!

Java 8 Default and Static method in Interface

In this tutorial we will discuss Java 8 Default and Static method in the interface and how can we implement it.

As a lot of changes have been introduced in Java 8 one of them is interface with methods implementation. They have made significant changes in interfaces & heavily in Collections APIs. Java 8 interface can have a method implemented with default or static keyword one at a time. However, we can have multiple methods implemented inside the interface.

The keyword allowed the implementation of the method is:

  • static
  • default

Interface with static method:

interface Tracker{
	void setup();
	
	static void displayChnages(){
		System.out.println("referse called");
	}
}

Interface with the default method:

public interface Log {

void testSetup();
	
	default void logger(){
		System.out.println("log setup successful and and logging begins");
	}
}

The Diamond problem: As we know that Java does not support multiple inheritances because it may lead to ambiguity. So how it will be handled in the interface now? Interface with the default and static methods are similar to abstract classes now.

The answer of the above problem is if two interfaces having the same method implemented and a single class implements both the interfaces then the compiler will throw an exception and the class has to override one of the interface method & if the class want to use the same implementation then it has to call the interface method from the overridden method.

The syntax to call the interface method from the overridden method is:

InterfaceName.super.methodName();

Let understand it with an example:

Create an interface Logger as below:

public interface Logger {

void testSetup();
	
	default void log(){
		System.out.println("logging begins");
	}
}

Create another interface CustomLogger as below:

public interface CustomLogger {

	default void log(){
		System.out.println("custom logging begins");
	}

       static void find(String str){
              System.out.println(String.format("finding %s in the logs .. ",str));
	}
}

Now let’s create a class DefaultMethodsExample that implements both the interface Logger and CustomLogger as below.

public class DefaultMethodsExample implements Logger,CustomLogger {

	@Override
	public void testSetup() {
		System.out.println("setup started ...");
	}

	@Override
	public void log() {
		CustomLogger.super.log();
	}

	public static void main(String[] args) {
		DefaultMethodsExample dmi = new DefaultMethodsExample();
		dmi.testSetup();
		dmi.log();
		CustomLogger.find("hello");
	}
}

As soon as you implement both the interfaces the compiler will start yelling with the following statements:

– Duplicate default methods named log with the parameters () and () are inherited
from the types CustomLogger and Logger

– The type DefaultMethodsExample must implement the inherited abstract method Logger.testSetup()

The first point forces the user to override the log method from one of the implementations. Once you run this class after resolving the above errors the output will be.

setup started ...
custom logging begins
finding hello in the logs. 

Note we have an override log method from CustomLogger Interface.

Recommended Read

java 8

Happy Learning !!!