Skip to content

Java 8 features project with practical coding examples covering Lambda Expressions, Functional Interfaces, Stream API, Date-Time API, Method & Constructor References, Default & Static Methods in Interfaces, Optional Class, and Function interfaces (Predicate, Function, Consumer, Supplier, BiFunction, UnaryOperator, BinaryOperator).

Notifications You must be signed in to change notification settings

Jayeshsarvade/Java_8_Features

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

📌 Java 8 Features Project This project demonstrates key Java 8 features with hands-on coding examples to help understand and apply modern Java concepts in real-world development. Covered topics include:

Lambda Expressions – Simplify anonymous class implementations using concise syntax

Functional Interfaces – Use interfaces with a single abstract method for lambda support

Stream API – Perform bulk data operations on collections in a functional style

Date and Time API – Improved, immutable, and time zone-aware classes under java.time

Method & Constructor References – Shorthand for calling existing methods using ::

Default & Static Methods in Interfaces – Extend interfaces without breaking existing implementations

Optional Class – Avoid NullPointerException with safe value handling

Predicate, Function, Consumer, Supplier, BiFunction, BiConsumer, etc. – Functional interfaces for powerful data manipulation

UnaryOperator & BinaryOperator – Specializations of Function/BiFunction for same-type input-output

Each feature is backed by clean, commented Java examples. Ideal for interview prep, learning modern Java, or refreshing core concepts.

  1. Lamda Expression: Lamda Expressions are similar to methods, but they do not need a name and they can be implemented right in the body method. Using lambda expression we don’t need to use any separate implementation class It is a replacement of anonymous inner class Example: (x,y)-> x+y.

i.e. 1.Not having any name. 2. Not having any return type. 3. not having modifier

• Steps to make any function as lamda Expression:

  1. Remove Modifier
  2. Remove return type
  3. Remove method name
  4. Place arrow

Eg.

  1. private void sayHello(){ System.out.println("Hello, World!"); } Ans. ()->{System.out.Println(“Hello, World!”)}

  2. Private void add(int a, int b){ System.out.println(a+b); } Ans. (int a, int b)->{System.out.println(a+b);}

  3. Private int getStringLength(String str){ Return str.length(); } Ans. (String str)->{ return str.length();}

Note :

  1. f body has one statement then we don’t need to use { } courly braces Ans. (String str)-> return str.length();

  2. Use Type inference, compiler guess the situation or context. Eg. Private int getStringLength(String str){ Return str.length(); } Convert to: Ans. (String str)->{ return str.length();} Convert to: Ans. (str)-> str.length(); // no return keyword and Datatype

Benefits of lamda Expression:

  1. To enable Functional Programming in java.
  2. To make code more readable, maintainable and concise code
  3. To enable parallel processing
  4. JAR file size reduction
  5. Elimination of shadow variables

Project location : Open in intellij Path: C:\Interview 2\Java 8 Features\Java_8_Features_Coding\Java_8_Features

  1. Stream API: Java Stream api for Bulk Data Operations On Collection.

  2. Date and Time API: Under the package java.time, java 8 offers a new date-time API • Issue with legacy Date and Calendar classes • Mutable: They are not thread-safe due to mutability, leading to unexpected bugs in concurrent environments. • Confusing API: Method names are misleading (e.g., getMonth() returns 0 for January), and inconsistencies make them hard to use. • Limited Functionality: Poor support for time zones, date arithmetic, and formatting compared to modern needs.

• In java 8 Date and time o LocalDate: Represents a date without a time zone. o LocalTime: Represents a time without a date or time zone. o LocalDateTime: Represents a date and time without a time zone. o ZonedDateTime: Represents a date and time with a time zone. o Instant: Represents an instantaneous point on the timeline, typically used for machine timestamps. o Duration: Represents a duration of time between two points in time. o Period: Represents a period of time between two dates. o DateTimeFormatter: Formats and parses dates and times.

  1. Method reference and Cunstructor reference(::) double colon: :: Operator Method and constructor references are a shorthand syntax for lambda expressions that simply call an existing method or constructor. They make your code cleaner and more readable. Reference Type Syntax Example
  2. Static Method Reference ClassName::staticMethod Math::abs
  3. Instance Method (on object) object::instanceMethod System.out::println
  4. Instance Method (of any object of a class) ClassName::instanceMethod String::toUpperCase
  5. Constructor Reference ClassName::new ArrayList::new
  • Eg. public void print(String s){ System.out.println(s); } public static void main(String[] args) { List students = Arrays.asList("radha", "krishna","jayesh"); MethodReference methodReference = new MethodReference(); students.forEach(methodReference::print);

Constructor Reference: Used when a lambda creates a new object.

  1. Default And Static methods in interface: Default methods in interface are those methods which are defined in the interface with the keyword default. Static methods in interface are those methods which are defined in the interface with the keyword static. static methods contain the complete definition of the function. Cannot be overridden or changed in the implementation class. You can call this method directly through interface name like StaticInterface.staticMethod(); We can add main method inside interface as well

  2. Functional Interface: A functional Interface is an interface that has exactly one abstract method, but can have number of default and static methods. To designate an interface as a functional interface, we don’t need to use the @FunctionalInterface annotation. We can invoke lambda expression by using functional interface.

Q. What is the advantage of this annotation? It restrict the interface to be a Functional interface. So if people have already used some lambda expression and some new team members added another abstract method in the interface all lambda expression will have errors

  1. Optional class | Java IO Improvements | Collection API Improvements The Optional class in Java (introduced in Java 8) is a container object which may or may not contain a non-null value. It is used to avoid NullPointerException and to represent the absence of a value more explicitly.

Key Features: • Creation: You can create an Optional using Optional.of(value), Optional.ofNullable(value), or Optional.empty(). • Methods: o isPresent(): Returns true if a value is present. o get(): Returns the value if present, else throws NoSuchElementException. o ifPresent(Consumer): Executes the given lambda if a value is present. o orElse(T other): Returns the value if present, otherwise returns other. o orElseGet(Supplier): Returns the value if present, otherwise gets a value from the supplier. o orElseThrow(): Returns the value if present, otherwise throws an exception. Usage Example: Optional name = Optional.ofNullable(getName()); name.ifPresent(n -> System.out.println(n.toUpperCase()));

Benefits: • Reduces null checks. • Makes APIs more readable and robust. • Encourages functional programming style. Common Use Cases: • Return type for methods that may not always return a value. • Chaining operations without worrying about nulls. Limitations: • Not intended for fields, only for return values. • Should not be used for every nullable reference, only where absence of value is meaningful. Package: java.util.Optional

  1. Predicate Class (Functional Interface): A Boolean valued function.

Methods:

  1. boolean test(T t);
  • one abstract method return true and false.
  • Eg. Predicate isEven = x->x%2==0; Int number = isEven.test(2); System.out.println(number); //true
  1. default Predicate and(Predicate<? super T> other):
  • checks the 2 conditions, both 2 condition should be true, then it will return true
  • Eg. Predicate startsWithLetterJ = x->x.toLowerCase().charAt(0)=='j'; Predicate endsWithLetterH = x->x.toLowerCase().charAt(x.length()-1)=='h'; Predicate and = startsWithLetterJ.and(endsWithLetterH);
  1. default Predicate or(Predicate<? super T> other)
  • checks the condition either one condition should be true then it will return true
  • eg. Predicate startsWithLetterJ = x->x.toLowerCase().charAt(0)=='j'; Predicate endsWithLetterH = x->x.toLowerCase().charAt(x.length()-1)=='h'; Predicate or = startsWithLetterJ.or(endsWithLetterH);\
  1. default Predicate negate()
  • Returns a predicate that represents the logical negation of this predicate
  • Eg. Predicate startsWithLetterJ = x->x.toLowerCase().charAt(0)=='j'; System.out.println(startsWithLetterJ.negate().test("JAYES"));
  1. static Predicate isEqual(Object targetRef) (Static method)
  • Returns a predicate that tests if two arguments are equal using Objects.equals().
  • Eg. Predicate ram = Predicate.isEqual("ram"); System.out.println(ram.test("ram"));
    1. Function Interface (@FunctionalInterface) In Java, the Function interface is a functional interface introduced in Java 8 as part of the java.util.function package. It represents a function that takes one input and returns one output. This is extremely useful in functional programming, lambda expressions, and stream API operations.
    • Eg. @FunctionalInterface public interface Function<T, R> { R apply(T t); }

    Methods:

    1. apply(T t):
    • Applies this function to the given argument.
    • Eg. Function<String, Integer> function = x->x.length(); System.out.println(function.apply("radha"));
    1. andThen(Function after)
    • First applies this function, then applies after
    • Eg. Function<String, String> function1 = x->x.toUpperCase(); Function<String, String> function2 = x->x.substring(0,3);

    Function<String, String> stringStringFunction = function1.andThen(function2); System.out.println(stringStringFunction.apply("jayesh"));

    1. compose(Function before)
    • First applies before, then applies this function.
    • Eg. Function<Integer, Integer> function1 = x -> x * 2; Function<Integer, Integer> function2 = x -> x * x * x; System.out.println(function1.andThen(function2).apply(3)); System.out.println(function2.andThen(function1).apply(3)); //using comparator System.out.println(function1.compose(function2).apply(3));
    1. identity() (Static method)
    • Returns a function that always returns its input argument.
    • Eg. Function<String, String > name = Function.identity(); System.out.println(name.apply("Jayesh"));
    1. Consumer Interface Consumer is a functional interface introduced in Java 8 in the java.util.function package. It represents an operation that takes a single input and returns no result. It's often used for performing side effects like printing, logging, modifying data, etc.

    Methods:

    1. accept(T t)
    • Performs the operation on the given argument
    • Eg. Consumer consumer = s -> System.out.println(s); consumer.accept("Jayesh");
    1. andThen(Consumer after)
    • Returns a composed Consumer that performs this operation, then the after
    • Eg. Consumer<List> listConsumer = li -> { for (Integer i : li) { System.out.println(i + 100); } }; Consumer<List> listConsumer1 = li->{ for (Integer i : li){ System.out.println(i); } }; listConsumer1.andThen(listConsumer).accept(Arrays.asList(1,2,3,4));
    1. Supplier Interface (@FunctionalInterface) The Supplier interface is a functional interface from java.util.function package introduced in Java 8. It represents a supplier of results — i.e., it takes no input but returns a value.

    Methods:

    1. T get();
    • Eg. Supplier supplier = ()->1; System.out.println(supplier.get());
    1. BiPredicate BiPredicate<T, U> is a functional interface from the package java.util.function introduced in Java 8. It represents a boolean-valued function (i.e., returns true or false) that accepts two input arguments of types T and U.

    Methods

    1. boolean test(T t, U u)
    • Tests a condition using two arguments.
    • Eg.
      1. BiPredicate<Integer, Integer> biPredicate = (x,y)->x%2==0 && y % 2==0; System.out.println(biPredicate.test(1,2)); //false
      1. BiPredicate<String, Integer> bipredicate = (str, y) -> str.length() == y; System.out.println(bipredicate.test("jayesh",6)); //true
    1. BiFunction BiFunction<T, U, R> is a functional interface from java.util.function (Java 8+). It represents a function that: • Takes two input arguments of types T and U • Returns a result of type R • It’s used when you want to combine or process two values and return a result. Methods
    2. R apply(T t, U u)
    • Applies this function to the given arguments
    • Eg. BiFunction<Integer, Integer, Integer> biFunction = (x, y) -> x * y; System.out.println(biFunction.apply(2, 5));
    1. andThen(Function<? super R, ? extends V>)
    • Chains another function to transform the result (same as function interface method andThen)
    1. BiConsumer BiConsumer<T, U> is a functional interface in the java.util.function package, introduced in Java 8. It represents an operation that takes two input arguments of types T and U, and returns no result (i.e., void).

    Methods

    1. void accept(T t, U u)
    • Performs an operation on the given two inputs
    • Eg. BiConsumer<Integer, Integer> biConsumer = (x,y)->{ System.out.println(x+y); }; biConsumer.accept(1,2);
    1. andThen(BiConsumer<? super T, ? super U> after)
    • Chains two BiConsumers in sequence
    1. UnaryOperator And BinaryOperator

    2. UnaryOperator: Takes one argument of type T, Returns a result of the same type T Eg.

    3. Function<String ,Integer> function = str->str.length(); // earlier we were using this interface however String denotes as input an Integer as a retyrn System.out.println(function.apply("jayesh")); // just because of the input datatype and returntype is different so that we are using FunctionInterface

    4. UnaryOperator unaryOperator = x->x*x; // here in this caseboth input and the return type is the same so we don't need to use FunctionInterface her System.out.println(unaryOperator.apply(2)); //we can simply use UnaryInterface so we don't need to add returntype here

    5. BinaryOperator

    • A specialization of BiFunction<T, T, T>: Takes two arguments of type T Returns a result of the same type
    • Eg. BiFunction<String, String, String> biFunction = (str, str1)-> str.concat(str1); System.out.println(biFunction.apply("jay", " Radha")); BinaryOperator binaryOperator = (str,str1)->str + str1; System.out.println(binaryOperator.apply("jai shri"," radha")); This is same as unaryOperator

About

Java 8 features project with practical coding examples covering Lambda Expressions, Functional Interfaces, Stream API, Date-Time API, Method & Constructor References, Default & Static Methods in Interfaces, Optional Class, and Function interfaces (Predicate, Function, Consumer, Supplier, BiFunction, UnaryOperator, BinaryOperator).

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published