The best way to map @OneToOne


@OneToOne

The best approach to bidirectional @OneToOne is to use @MapsId

Student entity

@Entity
@Data
@Table(name = "students")
public class Student implements Serializable {

    @Id
    @GeneratedValue
    private Integer id;
    private String name;
    private String email;

    @OneToOne(mappedBy = "student", cascade = CascadeType.ALL)
    private StudentDetails studentDetails;
}

StudentDetails entity

@Entity
@Data
@Table(name = "student_details")
public class StudentDetails implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String studentDetailsInfo;

    @OneToOne
    @JoinColumn(name = "student_id")
    @MapsId
    private Student student;
}

The best way to map @ManyToMany


@ManyToMany

Many to many relationships can be easily mapped by creating another table using @JoinTable as follows.

Student entity

@Data
@Table(name = "Student")
@Entity
public class Student implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String studentName;

    @ManyToMany
    @JoinTable(
        name = "student_task",
        joinColumns = @JoinColumn(name = "task_id"),
        inverseJoinColumns = @JoinColumn(name = "student_id")
    )
    private Set<Task> tasks = new HashSet<>();
}


Task entity

@Entity
@Data
@Table(name = "tasks")
public class Task implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String taskName;

    @ManyToMany(mappedBy = "tasks")
    private Set<Student> students = new HashSet<>();
}

How to avoid NullPointerException


java.lang.NullPointerException

When can it be thrown?

According to the JavaDoc, the following scenarios can be found.
  • Calling the instance method of a null object.
  • Accessing or modifying the field of a null object.
  • Taking the length of null as if it were an array.
  • Accessing or modifying the slots of null as if it were an array.
  • Throwing null as if it were a Throwable value.

How to avoid it?

  • Use Optional in Java 8
  • Call equals() and equalsIgnoreCase() methods on known objects.
  • Use valueOf() over toString()
public class NullCheckDemo {
   public static void main(String args[]){
       Integer i = null;
       System.out.println(i.toString());      //This throws NullPointerException
       System.out.println(String.valueOf(i)); //This returns null
   }
}
  • Use null-safe methods and libraries. Ex: Apache Commons StringUtils.
  • Use @NotNull and @Nullable annotations
  • Always check for nulls.
public class NullDemo {
    public static void main(String args[]){
        Integer i = null;

        if(i != null)
            System.out.println(i);
        else
            System.out.println("error occurred");
    }
}


Thread pool in Java


The Thread pool

Introduction

  • Executor implementations use thread pools.
  • The thread pool is a collection of worker threads that are ready to serve.
  • Creating new threads and manage them uses a big amount of data.
  • Worker threads in the thread pool will help to reduce this overhead of creating threads.
  • Tasks are submitted to the pool via an internal queue called blocking queue.
  • If there are more tasks than active threads, these tasks will be inserted into a blocking queue until a thread becomes available.
  • A common type of thread pool is the fixed thread pool.

Fixed thread pool

  • This has a specific number of running threads.
  • If a thread stops, this will replace with a new thread.
  • The main advantage of the fixed thread pool is it will limit the threads of an application.
  • It won't let the application exceed the limit of threads that the application handles.

Java ExecutorService


Java ExecutorService

Introduction

  • If an application has few threads, it can be used threads very easily using the above methods.
  • But if an application has many threads, it will be not easy to handle this.
  • Executors can be used to avoid this complexity.
  • The executor framework is a framework that can be used for creating, managing and executing threads.
  • This provides an asynchronous feature to Java applications.

Features of Executor service

  • Thread creation
    • Provides thread pool and various methods to create threads.
  • Thread Management
    • The thread pool will manage the life cycle of threads.
  • Thread Execution
    • Various methods will be provided
    • Thread schedulers can be used.

Executor interfaces in the Java Concurrency API

  • Executor
    • Provides a single method execute() to create a thread.
    • (new Thread(r)).start() can be replaced with e.execute(r)
  • ExecutorService
    • Also provides execute() method but this accepts both Runnable and Callable objects.
  • ScheduledExecutorService
    • This can be used to act as the asynchronous manner in Java
    • It can be used periodically and after a specific timeout.
    • Runnable and Callable tasks can be executed


Thread priority


Thread priority

  • Each thread has a priority.
  • It starts from 1 to 10 and the highest priority is 10 while the lowest is 1.
  • The default priority of the main thread is 5.
  • If you set the thread priority out of 10, it will give a compile-time error
Exception in thread "main" java.lang.IllegalArgumentException