Core Java Important Concepts for Interview

Java Version Features • Streams • Optional • Lambda Expressions • Functional Interfaces • Collections • Comparator • Method References

Converted from the provided Java8_Features.htm

1.1 Java Different Version Features

Java 8Java 11Java 21
  • Lambda Expressions
  • Functional Interfaces
  • Method References
  • Default Methods in Interfaces
  • Static Methods in Interfaces
  • Stream API
  • Date and Time API
  • Optional Class
  • Nashorn JavaScript Engine
  • Parallel Streams
  • CompletableFuture
  • Collectors Utility
  • Local-Variable Syntax for Lambda Parameters
  • New String Methods
  • New File Methods
  • HTTP Client (Standardized)
  • Collection Enhancements
  • Launch Single-File Programs
  • Record Patterns
  • Pattern Matching for switch
  • Virtual Threads
  • Sequenced Collections
  • String Templates
  • Scoped Values
  • Unnamed Patterns and Variables
  • Unnamed Classes and Instance Main Methods
  • Foreign Function & Memory API
  • Structured Concurrency
Source note: The original document presents these features grouped under Java 8, Java 11 and Java 21.

1.2 Java 8 Features

Streams

Intermediate operations and terminal operations.

Functional Interfaces

Function, BiFunction, Consumer, BiConsumer, Supplier, Predicate, BiPredicate, UnaryOperator and BinaryOperator.

Lambda Expressions

Concise implementation of functional interfaces.

Method References

Concise references to methods.

Default / Static Methods

Default and static methods in interfaces.

Optional

Container class for optional values.

Date and Time API

java.time API.

Parallel Streams

Parallel stream processing.

CompletableFuture

Asynchronous programming support.

Collectors Utility

Collecting and reducing Stream results.

Stream Operations

CategoryOperations / API
Intermediate operationsfilter (Predicate), map (Function), flatMap (Function<T, Stream<R>>), distinct, sorted (Comparator<T>), limit(n), skip(n), peek (Consumer<T>)
Terminal operationscollect(Collectors), forEach(Consumer), count(), anyMatch(Predicate<T>), allMatch(Predicate<T>), noneMatch(Predicate<T>), findFirst(), findAny(), reduce(BinaryOperator<T>)

Java 8 Map New Features

MethodSource-listed operation
forEachIterate over Map entries.
getOrDefaultGet a value or a default value.
putIfAbsentPut a value when absent.
computeIfAbsentCompute a value when absent.
computeIfPresentCompute a value when present.
computeCompute a new value.
mergeMerge a value with the existing value.
replaceReplace an existing value.
removeRemove an entry.

1.3 Aggregate (Reduction) Functions in Java 8 Streams

FunctionDescriptionExample
count() Returns the count of elements in the stream.
long c = list.stream().count();
sum() Returns the sum (only for primitive streams).
int s = list.stream()
    .mapToInt(i -> i)
    .sum();
min(Comparator) Returns the minimum element using a comparator.
Optional<Integer> min =
    list.stream().min(Integer::compare);
max(Comparator) Returns the maximum element using a comparator.
Optional<Integer> max =
    list.stream().max(Integer::compare);
average() Returns the average of elements (primitive streams).
OptionalDouble avg =
    list.stream()
        .mapToInt(i -> i)
        .average();
reduce(identity, accumulator) Reduces elements to a single value with identity.
int sum =
    list.stream()
        .reduce(0, (a, b) -> a + b);
reduce(accumulator) Same as above but returns Optional<T>.
Optional<Integer> total =
    list.stream()
        .reduce((a, b) -> a + b);
collect(Collectors.summarizingInt()) Returns summary statistics: count, sum, min, max, average.
IntSummaryStatistics stats =
    list.stream().collect(
        Collectors.summarizingInt(i -> i)
    );
collect(Collectors.joining()) Joins String elements.
String joined =
    list.stream().collect(
        Collectors.joining(", ")
    );
groupingBy Groups elements by a classifier function and applies aggregation.
list.stream()
    .collect(
        Collectors.groupingBy(
            Function.identity(),
            Collectors.counting()
        )
    );

1.4 Optional

The Optional class in Java 8 is a container object used to contain not-null objects. Optional is part of the java.util package and was introduced to reduce the risk of NullPointerException and provide a better way to handle optional values.

MethodReturn TypeDescription
empty()Optional<T>Returns an empty Optional instance.
of(T value)Optional<T>Returns Optional with non-null value; throws NullPointerException if null.
ofNullable(T value)Optional<T>Returns Optional of value or empty if null.
get()TReturns value if present; throws NoSuchElementException if not.
isPresent()booleanReturns true if value is present.
ifPresent(Consumer<T> action)voidExecutes action if value is present.
ifPresentOrElse(Consumer, Runnable)voidAdded in Java 9. Executes action if present, else runs Runnable.
filter(Predicate<T>)Optional<T>Returns same Optional if predicate matches, else empty.
map(Function<T,R>)Optional<R>Applies mapper function if value is present.
flatMap(Function<T, Optional<R>>)Optional<R>Similar to map but avoids nested Optionals.
orElse(T other)TReturns value if present; else returns other.
orElseGet(Supplier<T>)TReturns value if present; else returns value from Supplier.
orElseThrow()TReturns value if present; else throws NoSuchElementException.
orElseThrow(Supplier<E>)TReturns value or throws exception from supplier.

Optional Example

Optional<String> name =
    Optional.of("Srikanth");

name.ifPresent(
    n -> System.out.println(
        n.toUpperCase()
    )
);

String result =
    name.orElse("Default");

System.out.println(result);

Optional<String> emptyName =
    Optional.empty();

String result2 =
    emptyName.orElse("Default");

System.out.println(result2);

When to Use Optional

  • As a return type when the result might be absent.
  • To replace null checks.

1.5 Lambda Expression

Lambda expressions provide a concise way to implement the abstract method of a functional interface.

Lambda expressions let you write shorter, cleaner, and more expressive code, especially for functional interfaces.

They are extensively used with Streams, Collections, and multithreading.

Functional Interface
Lambda Expression
Concise Implementation

1.6 Functional Interfaces (SAM)

A functional interface is an interface that contains exactly one abstract method.

These interfaces are used primarily with lambda expressions and method references, enabling you to write cleaner and more concise code.

Functional InterfaceExample
Function<T, R>
Function<String, Integer> lengthFunction =
    str -> str.length();

System.out.println(
    lengthFunction.apply("Sree")
);
BiFunction<T, U, R>
BiFunction<Integer, Integer, Integer> sum =
    (a, b) -> a + b;

System.out.println(
    sum.apply(5, 3)
);
Consumer<T>
Consumer<String> consumer =
    name -> System.out.println(
        "Hello, " + name
    );

consumer.accept("Alice");
BiConsumer<T, U>
BiConsumer<String, Integer> print =
    (name, age) ->
        System.out.println(
            name + " is " + age +
            " years old"
        );

print.accept("Bob", 30);
Supplier<T>
Supplier<String> supplier =
    () -> "Hello from Supplier!";

System.out.println(
    supplier.get()
);
Predicate<T>
Predicate<String> isLongerThan5 =
    s -> s.length() > 5;

System.out.println(
    isLongerThan5.test("Hello")
);
BiPredicate<T, U>
BiPredicate<String, String> isEqual =
    (a, b) -> a.equalsIgnoreCase(b);

System.out.println(
    isEqual.test("Java", "java")
);
UnaryOperator<T>
UnaryOperator<String> toUpperCase =
    s -> s.toUpperCase();

System.out.println(
    toUpperCase.apply("hello")
);
BinaryOperator<T>
BinaryOperator<Integer> multiply =
    (a, b) -> a * b;

System.out.println(
    multiply.apply(4, 5)
);
RunnableListed in the source as a functional interface.
CallableListed in the source as a functional interface.
ComparableListed in the source as a functional interface.
ComparatorListed in the source as a functional interface.
@FunctionalInterface is optional, but it helps catch errors during compile-time.

Predicate Example

Predicate<Integer> isEven =
    number -> number % 2 == 0;

System.out.println(
    "Is 10 even? " +
    isEven.test(10)
);

Function Example

Function<String, Integer> stringLength =
    str -> str.length();

System.out.println(
    "Length of 'Hello': " +
    stringLength.apply("Hello")
);

1.7 Collection Internal Data Structure

The original Java8_Features.htm contains an embedded image for this section. The referenced image asset is not included as a separately accessible file in the uploaded HTML, so the visual diagram has not been recreated here.

Collection Internal Data Structure

This section is retained from the source document as a dedicated topic placeholder so the converted HTML preserves the original document structure.

1.8 Comparable vs Comparator

AspectComparableComparator
Packagejava.langjava.util
PurposeDefines natural ordering of objectsDefines custom ordering of objects
Methodint compareTo(T o)int compare(T o1, T o2)
Implemented ByThe class itselfA separate class or lambda
Affects Original Class?Yes — class must implement itNo — can be defined externally
Used WithCollections.sort(list) or Arrays.sort(array)Same, with custom comparator passed as argument
Java 8 EnhancementsNo major changeSupports lambda expressions and default methods like comparing, thenComparing
Example Use CaseSorting employees by id (natural order)Sorting employees by name, salary, etc. (custom)

1.13.1 Comparator Java 8 Enhancements

Comparator in Java 8 is more powerful. You can use static methods like:

Comparator.comparing() Comparator.thenComparing() Comparator.reversed()
people.sort(
    Comparator.comparing(Person::getAge)
              .thenComparing(Person::getName)
);

people.forEach(
    person ->
        System.out.println(
            person.getName()
        )
);

List<Integer> sortedArrayList =
    al.stream()
      .sorted(Comparator.reverseOrder())
      .collect(Collectors.toList());

int k = 2;

System.out.println(
    sortedArrayList.get(k - 1)
);

1.9 Method References

A method reference is essentially a shorthand notation for calling a method using a lambda expression.

Method references can be used in the context of functional interfaces (interfaces with a single abstract method), commonly used in places where lambda expressions are applicable.

Types of Method References

Reference to a Static Method

A static method in a class can be referred to with ClassName::staticMethodName.

Reference to an Instance Method of a Particular Object

You can refer to an instance method of an object using objectInstance::instanceMethodName.

Reference to an Instance Method of an Arbitrary Object of a Particular Type

This is useful when you don't have a specific object but want to refer to an instance method of an object of a specific type. It is often used with Streams.

Reference to a Constructor

You can refer to a constructor using the ClassName::new syntax. This is particularly useful when using factory methods or Streams.

ClassName::staticMethodName
objectInstance::instanceMethodName
Type::instanceMethodName
ClassName::new

Method references provide a more concise and expressive way to refer to methods and are especially useful with Java's functional programming features (like Streams). They can simplify your code by replacing lambda expressions where the lambda body is just calling a method.