Java 8: The funda now applies, Code Less and Develop More

Updated on :September 12, 2023

Java is the exemplary object-oriented language we’ve known so far. The applications developed using this programming language are robust, scalable and interactive. The Java Champion and Java One Rockstar- Kirk Pepperdine has quoted a beautiful line stating " 'Write once, run everywhere' is a great slogan, and Java has come closer to that dream than any other technology stack I've used."

Comparing the first version of Java with the latest one, there is a vast difference noticed in the coding styles. In Fact, the 8th version is undoubtedly awesome. Developers heaved a sigh of relief when they toured the new and amazing Java 8. The reason is penny plain, advancements in functionality and introduction to functional programming.

What else can be said when you have already developed camaraderie with Java 8.

I know the truth... You have. Being a hard-core Java Developer why not? I am a technical writer but when I went through the features, the first thought hit was "start developing". But then, I came back to the reality. wink

Java 8 carries that ease which I think no other technology does, allowing developers to develop outstanding applications integrated with the robust and flexible back-end.

You may be wondering why Java 8 is at the forefront today? Am I right? Of course, Yes! Just kidding…  This blog spills the beans of the advanced features and a small introduction to functional programming.

Then, what are we waiting for? Should we begin?

1. Lambda expression

Introducing the Lambda expression, Java has moved one step forward towards functional programming. It’s an anonymous function that allows developers to write a method in the same place where it’s pointing the class object.

Syntax of Lambda Expression:

(argument)->(body)

Quick Example

public class MusicFile_Main {
public static void main(String[] args) {
/* Implementing MusicFile interface using Lambda Expression */
MusicFile mFile = (String file) -> System.out.println("Playing Music:" + file);

/* Call Play */
mFile.Play("Pitbull - Give Me Everything ft. Ne-Yo, Afrojack, Nayer.mp4");
}
}
Output

Playing Music:Pitbull - Give Me Everything ft. Ne-Yo, Afrojack, Nayer.mp4

Code Explanation:

I have written a small piece of code that displays the music file name as output. There are two classes, the first one is MusicFile interface which consists of a void parameter function. The second is the main class that implements MusicFile interface and points to the filename using Lambda Expression and calls play method to play the file.

2. Type Annotation

This concept is also new to Java developers. According to Wikipedia, Type Annotation is a form of syntactic metadata that can be added in the Java code.

Developers can annotate different classes, variables, objects connected with the main class.  

The main purpose behind its implementation is to build strong checking types. Yup, it’s true, Java 8 does not provide type checking framework, but gives developers a wide room to implement a robust type checking framework which can be used as a pluggable module during compilation time.

Type Annotation Class consist of a list of methods but normally the three basic type annotation used are @Retention, @Target, @Documented;

Syntax of Type Annotation:

@Target({ElementType.FIELD, ElementType.METHOD})

Public @interface ABC{

}

Quick Example

DefaultClass (Source)
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
 
public @interface DefaultClass {
   String email();
 
}

 Novelist (Source)
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
 
public @interface Novelist {
   
   /* 'value' element is optional because we provided default constant value. */
   String value() default "ABC";
   
   /*Compulsory elements of Novelist*/
   
   String AuthorName();
   String BookDescription();
   String PublishDate();
     
}
 
TypeAnnotationMain (Source)
 
import java.lang.reflect.Field;
import java.lang.reflect.Method;
 
public class TypeAnnotationMain {
   
   @DefaultClass(email = "[email protected]")
   
   private String emailid;
   
@Novelist(AuthorName ="Rachael",BookDescription = "About Java", PublishDate = "12 November, 2015")
 
   public static void main(String[] args) {
    
  System.out.println("Let's Analyze the Data");
  Field[]datafield = TypeAnnotationMain.class.getDeclaredFields();
  for(Field datafie:datafield)
  {
         if(datafie.isAnnotationPresent(DefaultClass.class))
         {
  DefaultClass getDefaultClass= datafie.getAnnotation(DefaultClass.class);
  System.out.println("> Default value on field '" + datafie.getName() + "': " + getDefaultClass.email());
         }
  }
  System.out.println("\n");
  Method[] method = TypeAnnotationMain.class.getDeclaredMethods();
  for(Method methods:method)
  {
         if(methods.isAnnotationPresent(Novelist.class))
         {
/*Retriving values from the Novelist class*/
       Novelist getNovelist = methods.getAnnotation(Novelist.class);
  System.out.println("> Novelist value on field '" + methods.getName() + "': " + getNovelist.AuthorName());
  System.out.println("> Novelist value on field '" + methods.getName() + "': " + getNovelist.BookDescription());
  System.out.println("> Novelist value on field '" + methods.getName() + "': " + getNovelist.PublishDate());
 
         }
          else {
       
       System.out.printf("Novelist's class variables:",methods.getName());
      }
  if (methods.isAnnotationPresent(DefaultClass.class)) 
    {


       DefaultClass getDefault = methods.getAnnotation(DefaultClass.class);
     
    /* Get value of annotation */
       System.out.println("> Default value on method '" + methods.getName() + "': " +  getDefault.email());
   }
  }
   }
 
}
 
Output
 
Let's Analyse the Data
 
> Default value on field 'emailid': [email protected]


> Novelist value on field 'main': Rachael
> Novelist value on field 'main': About Java
> Novelist value on field 'main': 12 November, 2015

Before explaining the code would like to brief you about the annotation used in the example;

- @Documented: Marks the annotation for creating a Java Doc file wherein the use of different methods and consequential values are displayed as denoted

- @Retention: Indicates for how long the annotations are stored in the implementation file

        Below the options are listed:

         - @RetentionPolicy.Source: Annotations available after the class is compiled

         - @RetentionPolicy.Runtime: Annotations available during runtime

         - @RetentionPolicy.Class: Annotation available during class compilation

- @Target: Describes the subject to which the annotation can be applied.

Below the options are listed:

      - @ElementType.FIELD: Annotation type targets to variable declaration

      - @ElementType.METHOD: Annotation type targets to methods/functions declaration

      - @ElementType.Parameter: Annotation type targets to formal parameter declaration

Code Explanation:

I have created an example which consists of two interfaces and a main class. The first interface, DefaultClass consists of a single method that returns void. The second interface, Novelist consists of three different methods that return string value. TypeAnnotationMain is the main class where the logic of assigning and fetching the values from the interface is applied using element type annotations.

3. Repeating Annotation:

Repeating Annotation is also a new feature and it seems Java 8 has made it easy for developers to tackle vivid situation by allowing developers to use single annotation multiple times in the same class.

Syntax of Repeating Annotation:

@Alert(role = "Manager")

@Alert(role = "Administrator")

@Alert(role = "Developer")

Quick Example:

Manufacturer(Source)


import java.lang.annotation.Repeatable;
@Repeatable(value = Manufactures.class )
public @interface Manufacturer {
 
  public String name();
}
 
Manufactures(Source)
 
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
 
@Retention( RetentionPolicy.RUNTIME )
public @interface Manufactures {
 
  public Manufacturer[]value();
}
 
CarsDisplay(Source)

 @Manufacturer(name = "BMW")
 @Manufacturer(name = "Range Rover")
 @Manufacturer(name = "Mercedes")
 @Manufacturer(name = "Audi")
 
  
public class CarsDisplay {
 
public static void main(String[] args) {
 
 Manufacturer[] display = CarsDisplay.class.getAnnotationsByType(Manufacturer.class);
 System.out.println("The count of car manufacturers: "+ display.length);
 
 for(Manufacturer manufacture:display)
 {
 System.out.println("Car Name:" +manufacture.name());
 }


}

}

OutPut:
 
The count of car manufacturers: 4
Car Name:BMW
Car Name:Range Rover
Car Name:Mercedes
Car Name:Audi

Code Explanation:

The above example created is simple and easy to understand. Following the steps of type annotation example, I created two interfaces and a main class. The first interface which is Manufacturer consists of a name method that returns string value. The second interface consists of an array that points to Manufacturer annotation.

Before defining the Manufacturer interface, I have written a single line, i.e @Repeatable(value = Manufactures.class) states that the Manufacturer annotation can be used multiple times accessing the name method from the Manufactures interface. The main class, i.e. CarDisplay fetches the values from repeating annotation Manufacturer using getAnnotationBytype() method and displays the names of cars along with the total count as output.

4. Stream

Stream is again an important feature in Java 8. In early versions of Java, stream was simply used to read and write the file using BufferedReaderStream or File Input/Output Stream classes. This version is more advanced and carries Streams API  that support parallel processing concept.

We know that parallel processing means dividing the huge task into small chunks and then consolidate the results to get the final outcome. Java 8 Streams API offers a similar kind of mechanism to work with Java Collection.

Syntax of Stream:

int sum = widgets.stream()
     .filter(b -> b.getColor() == RED)
     .mapToInt(b -> b.getWeight())
     .sum();

Quick Example:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class LambdaExampleStream {

public static void main(String[] args) {

new LambdaExampleStream().UsingStream();

new LambdaExampleStream().UsingParallelStream();

}

private void UsingStream() {

/ Create object of AtomicInteger initializing it with `0` /

AtomicInteger AI = new AtomicInteger(0);

/ Create list of names /

List listnames = new ArrayList(Arrays.asList("Rachael Ray", "Kim Smith", "Jennifer Warren","Smashing Ray"));
listnames.stream()
.filter(name->name.endsWith("Ray"))
.forEach(name->{
/ Calculate with the previous value of count and increment by 1/
AI.getAndIncrement();

System.out.print(name);

});

 / Get value of `AtomicInteger` /
 System.out.println("\n Total match found using stream(): " + AI.get()); 

}
private void UsingParallelStream() {

/ Create object of AtomicInteger with initial value `0` /
AtomicInteger AI = new AtomicInteger(0);

/ Create list of names. /
List listnames = new ArrayList(Arrays.asList("Rachael Ray", "Kim Smith", "Jennifer Warren","Smashing Ray"));

listnames.parallelStream()
.filter(name -> name.endsWith("Smith"))
.forEach(name -> {

/ Get the previous value of count and increment it by `1` /
AI.getAndIncrement();

/ Print the name /
System.out.println(name);
});

/ Get value of `atomicInteger` /
System.out.println("Total match found using parallelStream(): " + AI.get());

  }

}


Output

Rachael Ray Smashing Ray
Total match found using stream(): 2
Kim Smith

Total match found using parallelStream(): 1

Code Explanation:

In the above example, I have created two methods namely UsingStream() and UsingParallelStream(). Both these methods have the same task of fetching the names from the arraylist but their approach is different.

-Stream: The stream method iterates one task at a time which eventually increases the loading time.

-Parallel Stream: Whereas, the parallel stream method divides the same task into small chunks and iterate each task individually. Therefore, the loading time is reduced and simultaneously the final output of the assigned task is also retrieved.

Here, I have also used the getAutoIncrement() method of Atomic Integer class that helps in evaluating the count of names ending with Ray and Smith. And, ultimately, the get() method displays the list of name one after the other as the ForEach loop starts evaluating the result.

5. Date & Time

Prior to Java 8, the standard of date & time classes was not up to the mark. The existing classes, java.util.Date and SimpleDateFormat classes are not thread safe resulting into concurrency issues during run-time. Therefore, developers had to end up writing lengthy date handling codes just to get accurate results.

Now, Java 8 is advanced and the classes developed are thread safe and immutable resulting into handling date-time functionality seamlessly and most importantly, the output is accurate. It has become possible after the introduction of Joda-time library i. Joda-time library has shaped the standards of date & time API and the improvement is also noticed in supporting classes like zone, duration, format and parsing.

It’s been noted that from Java 8 onwards, developers are asked to use java.time instead of java.util as the key element of the Java application.

Syntax of DateTime:

java.time.format.DateTimeFormatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");

Quick Example:

import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
 
public class DateTime {
 
   public static void main(String[] args) {
  
  try{
  String Friday = "Nov 25 2016";
  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
  LocalDate holiday = LocalDate.parse(Friday, formatter);
  System.out.printf("Successfully parsed String %s, date is %s%n", Friday, holiday);
 
  }catch(DateTimeException e){
         
         System.out.println("Invalid");
         e.printStackTrace();
  }
  
   }
 
}
Output:
Successfully parsed String Nov 25 2016, date is 2016-11-25

Code Explanation:

The above example of date parsing is easy and simple to understand. I have imported three main classes namely DateTimeExpection, LocalDate and DateFormatter.

DateTimeException is an Exception class that catches the invalid pattern which is thrown in the Date class.

LocalDate class securely parses date using parse method.

DateFormatter formats the string with the different patterns listed in the dateformatter class index.

Here, the discussion on the new enthralling features end. We will now move on to the interesting corner- Functional Programming which is the last chapter of this blog. Gosh! Developing above examples was so interesting. Felt like as if  I am a developer. But then, this was for a short span and you know what, I enjoyed coding...

Come Back, Come Back to the last chapter, Functional Programming!

It’s indeed the interesting approach to organise the code and make it understandable. Yes, it’s the fact,  just as doctor’s handwriting is jargon to us so do programming. But if developers arrange the code into small chunks defining the purpose, it becomes even easy for them to make modifications in the later stage.

Oops! I forgot to define the term functional programming. It’s a simple structure that developers create to evaluate the logic and avoid changing state and mutable data. Just as the slogan says Write once, run everywhere, functions also follow the same mechanism. Developers can create an abstract class defining different types of functions and use them when requisite.

This is it! Feel free to share your thoughts in the comment below...

Read Similar Blogs

Five Cost-Effective Benefits of Hiring a Java Development Firm

Five Cost-Effective Benefits of Hiring a Java Development Firm

Java is the most popular programming language in the world, thanks to its platform independence, utmost ease of use, and cross-platform compatibility. Being a h ... Read more

50 Essential Terms Associated with PHP

50 Essential Terms Associated with PHP

“Clean code always looks like it was written by someone who cares.”― Robert C. Martin (editor-in-chief of C++ Report magazine) When it come ... Read more

10 Key Questions To Ask a Python Development Agency Before You Hire Them

10 Key Questions To Ask a Python Development Agency Before You Hire Them

Software applications have an immense influence on our lives, and it is continuously empowering us to do things effortlessly. From booking an air ticket to stre ... Read more