Stream filter() in Java with examples

Syntax:

Stream<T> filter(Predicate<? super T> predicate)

Returns a stream consisting of the elements of this stream that match the given predicate.

To see how filter() works, let’s create a Player class:

public class Player {

    private String name;
    private int points;
    private boolean vip;
    //Constructor and standard getters

and create some data to play with:

Player peter = new Player("Peter Parker", 15, false);
Player sarah = new Player("Sarah Johnes", 200, true);
Player charles = new Player("Charles Chaplin", 150, false);
Player mary = new Player("Mary Poppins", 1, true);

List<Player> players = Arrays.asList(peter, sarah, charles, mary);

So, for example if we want to see only VIP players, before Java 8 our filter of players would looks like:

List<Player> vipPlayersJava7 = new ArrayList<>();
for (Player p : players) {
    if (p.isVip()) {
        vipPlayersJava7.add(p);
    }
}

How this can be done with Java 8 ? It is just a matter of single line as follows.

List<Player> vipPlayersJava8 = players.stream()
.filter(v -> v.isVip())
.collect(Collectors.toList());

We have passed a Predicate instance into the filter() method in the form of a Lambda expression.

We can also use a method reference, which is shorthand for a lambda expression:

List<Player> vipPlayerJava8MethodRef = players.stream()
        .filter(Player::isVip)
        .collect(Collectors.toList());

Also, we can use multiple conditions with filter(). For example, filter by VIP status and name:

List<Player> sarahAndVip = players.stream()
        .filter(p -> p.getName().startsWith("Sarah") && p.isVip())
        .collect(Collectors.toList());

Interface Segregation Principle

Clients should not be forced to depend upon interfaces that they do not use.

  • Make fine grained interfaces that are client specific
  • Many client specific interfaces are better than one “general purpose” interface
  • Keep your components focused and minimize dependencies between them
  • Notice relationship to the Single Responsibility Principle?
  • avoid ‘god’ interfaces

Liskov Subsitution Principle

If it looks like a duck and quacks like a duck but it needs batteries, you probably have the wrong abstraction.

  • By Barbara Liskov, in 1998
  • Objects in a program would be replaceable with instances of their subtypes WITHOUT altering the correctness of the program.
  • Violations will often fail the “Is a” test.
  • A Square “Is a” Rectangle
  • However, a Rectangle “Is Not” a Square

Open/Closed Principle

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

  • Your classes should be open for extension
  • But closed for modification
  • You should be able to extend a classes behavior, without modifying it.
  • Use private variables with getters and setters – ONLY when you need them.
  • Use abstract base classes

Difference between HashMap and HashSet in Java

HashSet

  1. HashSet class implements the Set interface
  2. In HashSet, we store objects(elements or values) e.g. If we have a HashSet of string elements then it could depict a set of HashSet elements: {“Hello”, “Hi”, “Bye”, “Run”}
  3. HashSet does not allow duplicate elements that mean you can not store duplicate values in HashSet.
  4. HashSet permits to have a single null value.
  5. HashSet is not synchronized which means they are not suitable for thread-safe operations until unless synchronized explicitly.[similarity]

HashSet example:

 

HashMap

  1. HashMap class implements the Map interface
  2. HashMap is used for storing key & value pairs. In short, it maintains the mapping of key & value (The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.) This is how you could represent HashMap elements if it has integer key and value of String type: e.g. {1->”Hello”, 2->”Hi”, 3->”Bye”, 4->”Run”}
  3. HashMap does not allow duplicate keys however it allows having duplicate values.
  4. HashMap permits single null key and any number of null values.
  5. HashMap is not synchronized which means they are not suitable for thread-safe operations until unless synchronized explicitly.[similarity]

HashMap example:

 

Difference between HashSet and HashMap in Java

HashMap Hash Set
HashMap  is an implementation of Map interface HashSet is an implementation of Set Interface
HashMap Stores data in form of  key-value pair HashSet Store only objects
Put method is used to add element in map Add method is used to add element is Set
In hash map hashcode value is calculated using key object Here member object is used for calculating hashcode value which can be same for two objects so equal () method is used to check for equality if it returns false that means two objects are different.
HashMap is faster than HashSet because unique key is used to access object HashSet is slower than Hashmap

 

NoClassDefFoundError vs ClassNotFoundException

ClassNotFoundException and NoClassDefFoundError occur when a particular class is not found at runtime. However, they occur at different scenarios.

NoClassDefFoundError:

Thrown if the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.

The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.

ClassNotFoundException:

Thrown when an application tries to load in a class through its string name using:

  • The forName method in class Class.
  • The findSystemClass method in class ClassLoader.
  • The loadClass method in class ClassLoader.

but no definition for the class with the specified name could be found. For example, you may have come across this exception when you try to connect to MySQL or Oracle databases and you have not updated the classpath with required JAR files. Most of the time, this exception occurs when you try to run an application without updating the classpath with required JAR files.

ClassNotFoundException NoClassDefFoundError
It is an exception. It is of type java.lang.Exception. It is an error. It is of type java.lang.Error.
It occurs when an application tries to load a class at run time which is not updated in the classpath. It occurs when java runtime system doesn’t find a class definition, which is present at compile time, but missing at run time.
It is thrown by the application itself. It is thrown by the methods like Class.forName(), loadClass() and findSystemClass(). It is thrown by the Java Runtime System.
It occurs when classpath is not updated with required JAR files. It occurs when required class definition is missing at runtime.

 

 

Default Methods in Java 8

In this article, I’ll try to explain what are default methods in Java 8, why they are useful and how they can be used to enhance the design of your code.

Default methods are added to Java 8 largely to support library designers by enabling them to write more evolvable interfaces. Java 8 introduces “Default Method” or (Defender methods) new feature, which allows developers to add new methods to the interfaces without breaking the existing implementation of these interfaces. Default methods are non-abstract and marked by the modifier default. It provides flexibility to allow the interface define implementation which will use as default in the situation where a concrete class fails to provide an implementation for that method.

Let’s consider this piece of code to understand how it works, in this example, I’ve just added a new default method newDefaultMethod() to the existing ‘old’ interface.

An existing implementation of that interface will successfully compile without errors.

 

Why Default Method?

Reengineering an existing JDK framework is always very complex. Modify one interface in JDK framework breaks all classes that extends the interface which means that adding any new method could break millions of lines of code. Therefore, default methods have introduced as a mechanism to extending interfaces in a backwards compatible way.

Default methods can be provided to an interface without affecting implementing classes as it includes an implementation. If each added method in an interface defined with implementation then no implementing class is affected. An implementing class can override the default implementation provided by the interface.

For Java 8, the JDK collections have been extended and forEach method is added to the entire collection (which work in conjunction with lambdas).

The same mechanism has been used to add Stream in JDK interface without breaking the implementing classes.

When to Use Default Method Over Abstract Classes?

After introducing Default Method, it seems that interfaces and abstract classes are same. However, they are still a different concept in Java 8.

Abstract classes can still do more in comparison to Java 8 interfaces:

  • An abstract class can have a constructor.
  • Abstract classes are more structured and can hold a state.

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation.

However, with abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods.

With interfaces, all fields are automatically public, static, and final, and all methods that you declare or define (as default methods) are public. In addition, you can extend only one class, whether or not it is abstract, whereas you can implement any number of interfaces.

Conceptually, the main purpose of defender methods is a backwards compatibility after an introduction of new features (as lambda functions) in Java 8.

Are the abstract classes still useful in that scenario?

Yes. They are still useful. They can contain non-static, non-final methods and attributes (protected, private in addition to public), which is not possible even with Java-8 interfaces.

Default Method and Multiple Inheritance Ambiguity Problems.

Since java class can implement multiple interfaces and each interface can define default method with same method signature, therefore, the inherited methods can conflict with each other.

Let’s check this example:

The above code will fail to compile with the following error:

java: class Impl inherits unrelated defaults for defaultMethod() from types InterfaceA and InterfaceB

In order to fix this class, we need to provide default method implementation:

Further, if we want to invoke default implementation provided by any of super interface rather than our own implementation, we can do so as follows:

 

Difference Between Default Method and Regular Method

Default Method is different from the regular method in the sense that default method comes with default modifier. Additionally, methods in classes can use and modify method arguments as well as the fields of their class but default method, on the other hand, can only access its arguments as interfaces do not have any state.

 

In summary, Default methods enable to add new functionality to existing interfaces without breaking older implementation of these interfaces.

When we extend an interface that contains a default method, we can perform following,

  • Not override the default method and will inherit the default method.
  • Override the default method similar to other methods we override in a subclass.
  • Redeclare default method as abstract, which force a subclass to override it.

JUnit – assertThat (Hamcrest) – part 3

Ok, it’s time to continue our series of examples Hamcrest matchers usage. Previous blog posts can be found here (part 1part 2).

  • endsWith()

Creates a matcher that matches if the examined String ends with the specified String.

 

  • equalTo()

Creates a matcher that matches when the examined object is logically equal to the examined object.

 

equalTo() can also be used on Arrays in which case it will check the length of the Array and ensure that all the values in the input test array are logically equal to the values of the specified array.

 

  • equalToIgnoringCase()

Creates a matcher of String that matches when the examined string is equal to the specified expectedString, ignoring case.

 

  • equalToIgnoringWhiteSpace()

Creates a matcher of String that matches when the examined string is equal to the specified expected String when whitespace differences are (mostly) ignored. To be exact, the following whitespace rules are applied:

  1. all leading and trailing whitespace of both the expected String and the examined string are ignored
  2. any remaining whitespace, appearing within either string, is collapsed to a single space before comparison

 

  • greaterThan()

Creates a matcher of Comparable object that matches when the examined object is greater than the specified value, as reported by the compareTo method of the examined object.

 

  • greaterThanOrEqualTo()

Creates a matcher of Comparable object that matches when the examined object is greater than or equal to the specified value, as reported by the compareTo method of the examined object.

 

  • hasEntry()

Creates a matcher for Maps matching when the examined Map contains at least one entry whose key equals the specified key and whose value equals the specified value.

 

  • hasKey()

Creates a matcher for Maps matching when the examined Map contains at least one key that satisfies the specified matcher.

 

  • hasValue()

Creates a matcher for Maps matching when the examined Map contains at least one value that is equal to the specified value.

 

  • hasItem()

Creates a matcher for Iterables that only matches when a single pass over the examined Iterable yields at least one item that is equal to the specified item. Whilst matching, the traversal of the examined Iterable will stop as soon as a matching item is found.

 

  • hasItems()

Creates a matcher for Iterables that matches when consecutive passes over the examined Iterable yield at least one item that is equal to the corresponding item from the specified items. Whilst matching, each traversal of the examined Iterable will stop as soon as a matching item is found.

 

  • hasSize()

Creates a matcher for Collections that matches when the size() method returns a value equal to the specified size.

 

  • instanceOf()

Creates a matcher that matches when the examined object is an instance of the specified type.

 

 

JUnit – assertThat (Hamcrest) – part 2

Let’s continue (you can find Hamcrest matchers – part 1 here) our series of examples how to write JUnit test with Hamcrest matchers usage.

  • comparesEqualTo()

Creates a matcher of a Comparable object that matches when the examined object is equal to the specified value, as reported by the compareTo method of the examined object. The value which, when passed to the compareTo method of the examined object, should return zero.

 

  • contains()

Various matchers which can be used to check if an input Iterable contains values. The order of the values is important and the number of items in the Iterable must match the number of values being tested.

Test if the input list contains all of the values, the order of items is important.

Test if the input list contains items which match all of the matchers in the input matchers list, the order of items is important.

 

  • containsInAnyOrder()

This one is like contains() but as the name suggest the order of items is not important.

 

  • containsString()

A matcher that matches if the examined String contains the specified String anywhere.

 

  • empty()

A matcher for Collections matching examined collections whose isEmpty method returns true.

 

  • emptyArray()

A matcher for arrays that matches when the length of the array is zero.

 

  • emptyCollectionOf()

A matcher for Collections matching examined collections whose isEmpty method returns true.

 

  • emptyIterable()

A matcher for Iterables matching examined iterable that yield no items.

 

  • emptyIterableOf()

A matcher for Iterables matching examined iterable that yield no items and is of the given type.