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());

Spring Boot Security and H2 console

The configuration shown below should be used only in a development environment and not in production.

After enabling Spring Security in your Spring Boot application, you will not be able to access the H2 database console anymore.

With its default settings under Spring Boot, Spring Security will block access to the H2 database console.

To be able to access the H2 database console under Spring Security you need to change these four things:

  • Enable h2 console in your application.properties file
spring.h2.console.enabled=true
  • Allow all access to the URL path /console/*.
httpSecurity.authorizeRequests().antMatchers("/").permitAll().and()
.authorizeRequests().antMatchers("/console/**").permitAll();
  • Disable CRSF (Cross-Site Request Forgery). By default, Spring Security will protect against CRSF attacks.
httpSecurity.csrf().disable();
  • Since the H2 database console runs inside a frame, you need to disable this in Spring Security.
httpSecurity.headers().frameOptions().disable();

So, the very, very simple security configuration that allows you to access h2-console should look like:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity.authorizeRequests().antMatchers("/").permitAll().and()
                .authorizeRequests().antMatchers("/console/**").permitAll();

        httpSecurity.csrf().disable();
        httpSecurity.headers().frameOptions().disable();
    }
}

After applying these changes and trying to access your h2-console

http://localhost:8080/h2-console/

You should see the h2-console login page:

Project Lombok

Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.

Project Lombok webpage: https://projectlombok.org/

How Lombok Works

  • Hooks in via the Annotation processor API
  • The AST (raw source code) is passed to Lombok for code generation before java continues.
  • Thus, produces properly compiled Java code in conjunction with the Java compiler

Project Lombok and IDEs

  • Since compiled code is changed, and source files are not, IDE’s can get confused by this.
  • Modern IDEs such as IntelliJ, Eclipse, Netbeans support Project Lombok
  • Plugin Installation may be necessary

Project Lombok Features

  • @Getter – Creates getter methods for all properties
  • @Setter – Creates setter for all non-final properties
  • @ToString – Generates String of classname, and each field separated by commas; Optional parameter to include field names; Optional parameter to include the call to the super toString method
  • @EqualsAndHashCode – Generates implementations of ‘equals(Object other) and hashCode(); By default will use all non-static, non-transient properties; Can optionally exclude specific properties.
  • @NoArgsConstructor – Generates no-args constructor; Will cause compiler error if there are final fields; Can optionally force, which will initialize final fields with 0 / false / null
  • @RequiredArgsContructor – Generates a constructor for all fields that are final or marked @NonNull; Constructor will throw a NullPointerException if any @NonNull fields are null.
  • @Data – Generates typical boilerplate code for POJOs, Combines – @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor; No constructor is generated if constructors have been explicitly declared.
  • @Value – The immutable variant of @Data; All fields are made private and final by default.
  • @NotNull – Set on a parameter of method or constructor and a NullPointerException will be thrown if the parameter is null.
  • @Builder – Implements the ‘builder’ pattern for object creation.
  • @SneakyThrows – Throw checked exceptions without declaring in calling method’s throws clause.
  • @Syncronized – A safer implementation of Java’s synchronized
  • @Log – Creates a Java util logger.
  • @Slf4j – Creates a SLF4J logger.

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:

import java.util.HashSet;
class HashSetDemo{ 
  public static void main(String[] args) {
     // Create a HashSet
     HashSet<String> hset = new HashSet<String>();
 
     //add elements to HashSet
     hset.add("AA");
     hset.add("BB");
     hset.add("CC");
     hset.add("DD");
 
     // Displaying HashSet elements
     System.out.println("HashSet contains: ");
     for(String temp : hset){
        System.out.println(temp);
     }
  }
}

HashSet contains: 
AA
BB
CC
DD

 

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:

import java.util.HashMap;
class HashMapDemo{ 
  public static void main(String[] args) {
     // Create a HashMap
     HashMap<Integer, String> hmap = new HashMap<Integer, String>();
 
     //add elements to HashMap
     hmap.put(1, "AA");
     hmap.put(2, "BB");
     hmap.put(3, "CC");
     hmap.put(4, "DD");
 
     // Displaying HashMap elements
     System.out.println("HashMap contains: "+hmap);
  }
}

HashMap contains: {1=AA, 2=BB, 3=CC, 4=DD}

 

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.

/**
 * Created by marom on 20/11/16.
 */
public interface SomeOldInterface {

    public void existingMethod();

    default public void newDefaultMethod() {

        System.out.println("New default method is added in the interface");

    }
}

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

/**
 * Created by marom on 20/11/16.
 */
public class SomeOldInterfaceImpl implements SomeOldInterface {

    public void existingMethod() {
        // existing implementation is here…
    }
}

 

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).

public interface Iterable<T> {
public default void forEach(Consumer<? super T> consumer) {
    for (T t : this) {
        consumer.accept(t);
    }
  }
}

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:

/**
 * Created by marom on 20/11/16.
 */
public interface InterfaceA {

    default void defaultMethod() {

        System.out.println("Interface A default method");

    }
}
/**
 * Created by marom on 20/11/16.
 */
public interface InterfaceB {

    default void defaultMethod() {

        System.out.println("Interface B default method");

    }
}
/**
 * Created by marom on 20/11/16.
 */
public class InterfaceABImpl implements InterfaceA, InterfaceB {

}

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:

/**
 * Created by marom on 20/11/16.
 */
public class InterfaceABImpl implements InterfaceA, InterfaceB {

    public void defaultMethod() {
        // 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:

/**
 * Created by marom on 20/11/16.
 */
public class InterfaceABImpl implements InterfaceA, InterfaceB {

    public void defaultMethod() {
        // default method implementation
        InterfaceA.super.defaultMethod();
    }
}

 

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.

Watching a Directory for Changes

Watch Service Overview

The WatchService API is fairly low level, allowing you to customise it. You can use it as is, or you can choose to create a high-level API on top of this mechanism so that it is suited to your particular needs. The WatchService API lets you receive notification events upon changes to the subject (directory or file).

The steps involved in implementing the API are:

  • Create a WatchService. This service consists of a queue to holdWatchKeys
  • Register the directory/file you wish to monitor with this WatchService
  • While registering, specify the types of events you wish to receive (create, modify or delete events)
  • You have to start an infinite loop to listen to events
  • When an event occurs, a WatchKey is placed into the queue
  • Consume the WatchKey and invoke queries on it

Let’s follow this via an example. We create a DirWatcher Java program whose responsibility is to watch a particular directory (Downloads in my case). The steps are provided below:

1. Creating an WatchService object:

WatchService  watchService = FileSystems.getDefault().newWatchService();

2. Obtain a path reference to your watchable directory. I suggest you parameterize this directory so you don’t hard code the file name.

path = Paths.get(System.getProperty("user.home") + "/Downloads");

3. The next step is to register the directory with the WatchService for all types of events:

path.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);

When registering an object with the watch service, you specify the types of events that you want to monitor. The supported StandardWatchEventKinds event types follow:

  • ENTRY_CREATE – A directory entry is created.
  • ENTRY_DELETE – A directory entry is deleted.
  • ENTRY_MODIFY – A directory entry is modified.
  • OVERFLOW – Indicates those events might have been lost or discarded. You do not have to register for the OVERFLOW event to receive it.

4. Initiate the infinite loop and start taking the events:

while(true) {
    try {
        key = watchService.take();
.
.
.

    } catch (InterruptedException e) {
        System.out.println("InterruptedException: "+e.getMessage());
    }

 

5. Run through the events on the key:

for (WatchEvent<?> event : key.pollEvents()) {
      WatchEvent.Kind<?> kind = event.kind();
      System.out.println("Event on " + event.context().toString() + " is " + kind);
 }

For example, if you modify or delete the Download directory, you would see statement as shown below on the console respectively:

Event on newFile.txt is ENTRY_CREATE
Event on newFile.txt is ENTRY_MODIFY

 

Example source code:

import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;

/**
 * Created by marom on 28/09/16.
 */
public class DirWatcher {


        private Path path = null;
        private WatchService watchService = null;

        protected void init() {
            path = Paths.get(System.getProperty("user.home") + "/Downloads");
            try {
                watchService = FileSystems.getDefault().newWatchService();
                path.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
            } catch (IOException e) {
                System.out.println("IOException"+ e.getMessage());
            }
        }


        protected void doRounds() {
            WatchKey key = null;
            while(true) {
                try {
                    key = watchService.take();
                    for (WatchEvent<?> event : key.pollEvents()) {
                        WatchEvent.Kind<?> kind = event.kind();
                        System.out.println("Event on " + event.context().toString() + " is " + kind);
                    }
                } catch (InterruptedException e) {
                    System.out.println("InterruptedException: "+e.getMessage());
                }
                boolean reset = key.reset();
                if(!reset)
                    break;
            }
        }
}

 

public class Main {

    public static void main(String[] args) {

        DirWatcher watcher = new DirWatcher();
        watcher.init();
        watcher.doRounds();
    }
}

 

Simple Jersey example with Intellij IDEA Ultimate and Tomcat

Jersey

RESTful Web Services in Java.

Jersey is a reference implementation of the JAX-RS 2.0 API. Jersey provides it’s own API that extends the JAX-RS toolkit with additional features and utilities to further simplify RESTful service and client development.

In this example I will be using:

  • IntelliJ Idea Ultimate 2016.2
  • Jersey 2.23.2 (latest stable release of Jersey as of time of writing)
  • JDK 8
  • Tomcat 8.0.35

Create new project

To create a new project, open up the New Project dialog in IntelliJ. In the left menu, select Java Enterprise. To the right, select Web Application and ensure that Create web.xml is checked.

newproject

 

Add Maven support

To add Maven to your project, right-click on your project’s name in the Project sidebar and select Add Framework Support.

In the Add Frameworks Support, select Maven.

Once this is done, the pom.xml file will open in the editor. You will need to enter at least a groupId, usually your package name. At this point, it is helpful to enable auto-importing for library dependencies.

maven

Add Jersey dependencies to the Maven pom.xml file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.programmerscuriosity</groupId>
    <artifactId>SimpleJersey</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>${jersey.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <jersey.version>2.23.2</jersey.version>
    </properties>
    
</project>

 

Create a Resource

Inside of the src/main/java directory, create a new package matching your groupId.

And then create a simple java class – MyResource in my case.

package com.programmerscuriosity;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * Created by marom on 27/09/16.
 */
@Path("myresource")
public class MyResource {

    /**
     * Method handling HTTP GET requests. The returned object will be sent
     * to the client as "text/plain" media type.
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getIt() {
        return "Got it!";
    }
}

Modify index.jsp file by adding a link to the Jersey resource

<html>
  <head>
    <title>Simple Jersey</title>
  </head>
  <body>
  <p><a href="rest/myresource">Jersey resource</a>
  </body>
</html>

 

Check if Tomcat is configured properly.

tomcat-configuration

tomcat-deployment

 

Configure your servlet

Modify your web.xml file

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.programmerscuriosity</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>

 

Before we run our application, first we need to add Jersey jars to the /WEB-INF/lib directory

add-artifacts

After selecting all jars right click and choose “Put into /WEB-INF/lib

Run your Application

jersey-resource
got-it

 

DONE!

 

 

Git for an absolute beginners

Before I started using Git on my personal and then on commercial projects, I was using for many years  Subversion – svn in short. SVN is still very popular but Git earned its strong position as well by being used in large and small projects for more than 10 years already.

Installing Git

The official website of Git has detailed information about installing on Linux, Mac, or Windows. In this case, I will be using Ubuntu 16.04 for demonstration purposes, and installing git in Linux (Ubuntu) is simple as typing:

marom@marom-E7440:~$ sudo apt-get install git

Before we dive into configuration and will start using Git a bit of terminology introduction is necessary.

Here’s the git terminology:

  • master – the repository’s main branch. Depending on the workflow it is the one people work on or the one where the integration happens
  • clone – copies an existing git repository, normally from some remote location to your local environment.
  • commit – submitting files to the repository (the local one); in other VCS it is often referred to as “checkin”
  • fetch or pull – is like “update” or “get latest” in other VCS. The difference between fetch and pull is that pull combines both, fetching the latest code from a remote repo as well as performs the merging.
  • push – is used to submit the code to a remote repository
  • remote – these are “remote” locations of your repository, normally on some central server.
  • SHA – every commit or node in the Git tree is identified by a unique SHA key. You can use them in various commands in order to manipulate a specific node.
  • head – is a reference to the node to which our working space of the repository currently points.
  • branch – is just like in other VCS with the difference that a branch in Git is actually nothing more special than a particular label on a given node. It is not a physical copy of the files as in other popular VCS.

Initial Configuration

We need to configure our name and email. You can do it as follows, replacing the values with your own name and email.

marom@marom-E7440:~$ git config --global user.name "Courious Programmer"
marom@marom-E7440:~$ git config --global user.email "blog@programmerscuriosity.com"

It is important to note that if you do not set your name and email, certain default values will be used.

Create a new Git Repository

Before starting, let’s create a new directory where the git repository will be created and ‘move’ into it.

marom@marom-E7440:~/SmallProjects$ mkdir blogGitIntroduction
marom@marom-E7440:~/SmallProjects$ cd blogGitIntroduction/
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ 

Now we can initialize our first git repository.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git init
Initialized empty Git repository in /home/marom/SmallProjects/blogGitIntroduction/.git/

To check the status of our repository git status command can be used.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)

Create and commit a new file

The next step is to create a new file and add some content to it.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ touch blogpost.txt

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ echo "Hello, Git World!" > blogpost.txt

Let’s check what happen in our git repository.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	blogpost.txt

nothing added to commit but untracked files present (use "git add" to track)

To “register” the file for committing we need to add it to git using:

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git add blogpost.txt 

And again, let’s check what happen in our git repository.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git add secondFile.txt 
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git commit -m "add second file to the project"
[master 763b757] add second file to the project
 1 file changed, 1 insertion(+)
 create mode 100644 secondFile.txt

 

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

	new file:   blogpost.txt

We can now commit it to the repository.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git commit -m "add first file to the project"
[master (root-commit) 55db76b] add first file to the project
 1 file changed, 1 insertion(+)
 create mode 100644 blogpost.txt

Let’s add another file to the project.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ echo "this is text from second file in project" > secondFile.txt
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git add secondFile.txt 
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git commit -m "add second file to the project"
[master 763b757] add second file to the project
 1 file changed, 1 insertion(+)
 create mode 100644 secondFile.txt

 

Create a (feature) branch

Branching and merging is what makes Git so powerful and for what it has been optimised, being a distributed version control system (VCS). Indeed, feature branches are quite popular to be used with Git. Feature branches are created for every new kind of functionality you’re going to add to your system and they have usually deleted afterwards once the feature is merged back into the main integration branch (normally the master branch). The advantage is that you can experiment with new functionality in a separate, isolated “playground” and quickly switch back and forth to the original “master” branch when needed. Moreover, it can be easily discarded again (in case it is not needed) by simply dropping the feature branch. But let’s get started and create the new feature branch:

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git branch new-feature-branch

To see a list of all branches we need to use git branch command.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git branch
* master
  new-feature-branch

A star next to master branch indicates that this is a current branch.

Let’s switch to this newly created branch and modify one of the files.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git checkout new-feature-branch 
Switched to branch 'new-feature-branch'
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git branch
  master
* new-feature-branch
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ echo "Let's modify file in the branch" >> blogpost.txt
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ cat blogpost.txt 
Hello, Git World!
Let's modify file in the branch

And then add and commit it to the branch.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git add blogpost.txt 
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git commit -m "modify file on the branch"
[new-feature-branch 3a30916] modify file on the branch
 1 file changed, 1 insertion(+)

 

Ok, it’s time to complicate it and cause some conflicts. To do this we need to switch to ‘master’ branch and modify the blogpost.txt file.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git checkout master
Switched to branch 'master'
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git branch
* master
  new-feature-branch
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ echo "This change was done on master branch" >> blogpost.txt
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ cat blogpost.txt 
Hello, Git World!
This change was done on master branch

 

If you need to commit a file that was already added to the git repository you can use command ‘commit -a -m’

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git commit -a -m "change blogpost file"
[master 1a139b5] change blogpost file
 1 file changed, 1 insertion(+)

Merge and resolve conflicts

The next step would be to merge our feature branch back into ‘master’. This is done by using the merge command.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git merge new-feature-branch 
Auto-merging blogpost.txt
CONFLICT (content): Merge conflict in blogpost.txt
Automatic merge failed; fix conflicts and then commit the result.
marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ cat blogpost.txt 
Hello, Git World!
<<<<<<< HEAD
This change was done on master branch
=======
Let's modify file in the branch
>>>>>>> new-feature-branch

Edit file and resolve conflict and commit changes to the branch.

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ cat blogpost.txt 
Hello, Git World!

This change was done on master branch

Let's modify file in the branch

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git commit -a -m "resolve merge conflict"
[master 7e2abc0] resolve merge conflict

 

Rollback

What if we want to undo everything back to the state before the commit?

First, we need to get SHA identifiers (unique ‘id’ for each node in git tree).

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git log
commit 4afb2d5caf73f48be16cc78875b8fe58c72ce4dd
Author: Courious Programmer <blog@programmerscuriosity.com>
Date:   Sun Sep 11 10:02:16 2016 +0200

    prepare for rollback

commit 7e2abc0dc4f56672bf0f209551698c942dbc7071
Merge: 1a139b5 3a30916
Author: Courious Programmer <blog@programmerscuriosity.com>
Date:   Sun Sep 11 09:57:50 2016 +0200

    resolve merge conflict

commit 1a139b5dd7a9f42e4f7f570081b65dbc4d27529b
Author: Courious Programmer <blog@programmerscuriosity.com>
Date:   Sun Sep 11 09:37:40 2016 +0200

    change blogpost file

commit 3a309165db700a00fbe1a0f2451700c59532d629
Author: Courious Programmer <blog@programmerscuriosity.com>
Date:   Sun Sep 11 09:26:56 2016 +0200

 

and then move back in time to the desired node/commit

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git reset --hard 7e2abc0
HEAD is now at 7e2abc0 resolve merge conflict

 

marom@marom-E7440:~/SmallProjects/blogGitIntroduction$ git log
commit 7e2abc0dc4f56672bf0f209551698c942dbc7071
Merge: 1a139b5 3a30916
Author: Courious Programmer <blog@programmerscuriosity.com>
Date:   Sun Sep 11 09:57:50 2016 +0200

    resolve merge conflict

commit 1a139b5dd7a9f42e4f7f570081b65dbc4d27529b
Author: Courious Programmer <blog@programmerscuriosity.com>
Date:   Sun Sep 11 09:37:40 2016 +0200

    change blogpost file

commit 3a309165db700a00fbe1a0f2451700c59532d629
Author: Courious Programmer <blog@programmerscuriosity.com>
Date:   Sun Sep 11 09:26:56 2016 +0200

    modify file on the branch

commit 763b75761c9d95a68d1d1e56bd4d2b0390c03379
Author: Courious Programmer <blog@programmerscuriosity.com>
Date:   Sat Sep 10 19:13:28 2016 +0200

 

And that’s it. It is everything that is needed to start using git. I have covered here only simple commands. For more advanced commands and explanations I highly recommend reading this book: Pro GIT.

JUnit – assertThat (Hamcrest) – part 1

Hamcrest is a framework for creating matcher objects. These matcher objects are predicates and are used to write rules which can be satisfied under certain conditions. They are most often used in testing. Hamcrest lets us step beyond simple JUnit asserts and enables us to craft very specific and readable verification code. Hamcrest has the target to make tests as readable as possible. In general, the Hamcrest error messages are also much easier to read. Using Hamcrest matchers also provides more type safety as these matchers uses generics.

Simple Matchers

  • any()
@Test
public void anyMatcherExample() {

    int age = 30;
    assertThat(age, is(any(Integer.class)));        
}
  • anything()
@Test
public void anythingMatcherExample() {

    Integer age = 30;
    assertThat(age, is(anything()));
}
  • arrayContaining()

Does the array contain all given items in the order in which they are input to the matcher?

@Test
public void arrayContainingMatcherExample() {

    String[] names = {"Jon", "Peter", "Paul"};
    assertThat(names, is(arrayContaining("Jon", "Peter", "Paul")));
}
  • arrayContainingInAnyOrder()

Does the array contain all the given items? Length of the array must match the number of matchers, but their order is not important.

@Test
public void arrayContainingInAnyOrderMatcherExample() {

    String[] names = {"Jon", "Peter", "Paul"};
    assertThat(names, is(arrayContainingInAnyOrder("Peter", "Paul", "Jon")));
}
  • arrayWithSize()

Does the input array have exactly the specified length?

@Test
public void arrayWithSizeMatcherExample() {

    String[] names = {"Jon", "Peter", "Paul"};
    assertThat(names, is(arrayWithSize(3)));
}
@Test
public void arrayWithSizeGreaterThanMatcherExample() {

    String[] names = {"Jon", "Peter", "Paul"};
    assertThat(names, is(arrayWithSize(greaterThan(2))));
}
  • closeTo()

Matcher which can be used with either Double or BigDecimal to check if a value is within a specified error margin of an expected value.

@Test
public void closeToDoubleMatcherExample() {

    Double temperature = 25.5;
    assertThat(temperature, closeTo(25.0, 0.5));
}
@Test
public void closeToBigDecimalMatcherExample() {

    BigDecimal totalValue = new BigDecimal(234.00);
    assertThat(totalValue, closeTo(new BigDecimal(230.0), new BigDecimal(5)));
}