How do I use the BiConsumer functional interface in Java?

The BiConsumer interface in Java is part of the java.util.function package and is used when we need to perform an operation that takes two input arguments and does not return any result. It is a functional interface commonly used in lambda expressions or functional programming scenarios.

Key Features:

  1. It accepts two arguments of potentially different types.
  2. It does not return a result (void return type).
  3. It is primarily used for side effect operations (e.g., printing, modifying objects, etc.).

Method in BiConsumer:

  • void accept(T t, U u): Performs this operation on the given arguments.
  • Additionally, it has a default method:
    • default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after): Returns a composed BiConsumer that performs the operation of this BiConsumer first, followed by the after operation.

Example Usage:

Basic Example with Lambda

package org.kodejava.util.function;

import java.util.function.BiConsumer;

public class BiConsumerExample {
  public static void main(String[] args) {
    // Create a BiConsumer that adds two numbers and prints the result
    BiConsumer<Integer, Integer> addAndPrint =
            (a, b) -> System.out.println("Sum: " + (a + b));

    // Use the BiConsumer
    addAndPrint.accept(10, 20); // Output: Sum: 30
  }
}

Using BiConsumer to Manipulate a Map

The BiConsumer is often used with collections such as Map.

package org.kodejava.util.function;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

public class BiConsumerWithMap {
  public static void main(String[] args) {
    // Map of items
    Map<String, Integer> items = new HashMap<>();
    items.put("Apples", 10);
    items.put("Oranges", 20);
    items.put("Bananas", 30);

    // Define a BiConsumer to print key-value pairs
    BiConsumer<String, Integer> printEntry =
            (key, value) -> System.out.println(key + ": " + value);

    // Iterate through each entry in the map
    items.forEach(printEntry);
  }
}

Output:

Apples: 10
Bananas: 30
Oranges: 20

Combining BiConsumers with andThen

The andThen method allows chaining multiple BiConsumer operations.

package org.kodejava.util.function;

import java.util.function.BiConsumer;

public class BiConsumerAndThen {
  public static void main(String[] args) {
    BiConsumer<String, Integer> print =
            (key, value) ->
                    System.out.println("Key: " + key + ", Value: " + value);

    BiConsumer<String, Integer> multiplyValue =
            (key, value) ->
                    System.out.println("Multiplied Value for " + key + ": " + (value * 2));

    // Combine the two BiConsumers
    BiConsumer<String, Integer> combinedBiConsumer = print.andThen(multiplyValue);

    // Use the combined BiConsumer
    combinedBiConsumer.accept("Apples", 10);
  }
}

Output:

Key: Apples, Value: 10
Multiplied Value for Apples: 20

Scenarios to use BiConsumer:

  1. Iteration and processing:
    • Iterate through a Map and perform operations on key-value pairs.
  2. Side effects:
    • Logging, printing results, or modifying shared data structures.
  3. Chaining behaviors:
    • Chain operations on a pair of inputs using andThen.

Keynotes:

  • Be cautious about side effects as BiConsumer is typically used when a return value is not required.
  • The andThen method helps in composing behaviors, making the interface more powerful.

How do I use the Predicate functional interface in Java?

The Predicate class in Java is a functional interface introduced in Java 8 under the java.util.function package. It is used to test a condition on an input and return a boolean value (true or false). Predicates are often used in lambda expressions or method references to filter data or apply conditional logic.

Here’s how we can use the Predicate class in Java:

Basic Predicate Usage

The Predicate interface has a single abstract method:

boolean test(T t);

We implement this method to provide our condition logic.

Example:

package org.kodejava.util.function;

import java.util.function.Predicate;

public class PredicateExample {
    public static void main(String[] args) {
        // Create a predicate that checks if a number is greater than 10
        Predicate<Integer> isGreaterThan10 = number -> number > 10;

        // Test the condition
        System.out.println(isGreaterThan10.test(15)); // Output: true
        System.out.println(isGreaterThan10.test(8));  // Output: false
    }
}

Chaining Predicates

Predicates provide methods to combine multiple conditions:
and() – Combines two predicates with logical AND.
or() – Combines two predicates with logical OR.
negate() – Negates the predicate (logical NOT).

Example:

package org.kodejava.util.function;

import java.util.function.Predicate;

public class PredicateChainingExample {
    public static void main(String[] args) {
        Predicate<Integer> isEven = number -> number % 2 == 0;
        Predicate<Integer> isGreaterThan5 = number -> number > 5;

        // Chain predicates
        Predicate<Integer> isEvenAndGreaterThan5 = isEven.and(isGreaterThan5);
        Predicate<Integer> isEvenOrGreaterThan5 = isEven.or(isGreaterThan5);

        // Test
        System.out.println(isEvenAndGreaterThan5.test(8));  // Output: true
        System.out.println(isEvenAndGreaterThan5.test(3));  // Output: false
        System.out.println(isEvenOrGreaterThan5.test(3));   // Output: false
        System.out.println(isEvenOrGreaterThan5.test(7));   // Output: true
    }
}

Using Predicate in Collections

The Predicate interface is extensively used in working with Streams or filtering collections.

Example:

package org.kodejava.util.function;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class PredicateWithStreams {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Carol", "Mallory");

        // Create a predicate that tests if the string length is greater than 3
        Predicate<String> lengthGreaterThan3 = name -> name.length() > 3;

        // Filter and collect using the predicate
        List<String> filteredNames = names.stream()
                .filter(lengthGreaterThan3)
                .collect(Collectors.toList());

        // Output: [Alice, Carol, Mallory]
        System.out.println(filteredNames);
    }
}

Using Predicate with Default Methods

isEqual()

This static method evaluates if an object is equal to a predefined value.

Example:

package org.kodejava.util.function;

import java.util.function.Predicate;

public class PredicateIsEqualExample {
    public static void main(String[] args) {
        Predicate<String> isEqualToMark = Predicate.isEqual("Alice");

        // Output: true
        System.out.println(isEqualToMark.test("Alice"));
        // Output: false
        System.out.println(isEqualToMark.test("Bob"));
    }
}

Custom Predicate Usage

We can create our own predicate and pass it around in our code.

Example:

package org.kodejava.util.function;

import java.util.function.Predicate;

public class CustomPredicateExample {
    public static void main(String[] args) {
        // A custom method accepting a predicate
        testPredicate(value -> value > 10);

        // Another predicate for custom logic
        Predicate<Integer> isOdd = value -> value % 2 != 0;
        // Output: true
        System.out.println(isOdd.test(7));
    }

    static void testPredicate(Predicate<Integer> predicate) {
        // Output: true
        System.out.println(predicate.test(15));
    }
}

Summary

  • The Predicate interface is used for conditional checks and filtering data.
  • It works seamlessly with lambda expressions and method references.
  • You can combine multiple predicates using and, or, and negate.

This makes Predicate a very powerful and convenient tool for functional programming in Java!

How do I add an object to the beginning of Stream?

To add an object to the beginning of a list using Java Streams, we typically cannot directly prepend an object in a stream-friendly way because Streams themselves are immutable and don’t directly modify the original collection. However, we can achieve this by creating a new list with the desired order.

Here’s how we can approach it:

package org.kodejava.stream;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamBeginningAdd {
    public static void main(String[] args) {
        List<String> originalList = Arrays.asList("B", "C", "D");
        String newElement = "A";

        // Add the new element at the beginning using Stream
        List<String> updatedList = Stream.concat(Stream.of(newElement), originalList.stream())
                .collect(Collectors.toList());

        // Output: [A, B, C, D]
        System.out.println(updatedList);
    }
}

Explanation:

  1. Stream.of(newElement): Wraps the new element as a single-element stream.
  2. originalList.stream(): Converts the existing list into a stream.
  3. Stream.concat(): Combines the two streams — placing the newElement stream first and the original list’s stream second.
  4. collect(Collectors.toList()): Materializes (collects) the combined stream into a new list.

This ensures immutability of the original list and creates a new list with the desired order.

How do I get number of each day for a certain month in Java?

You can get the number of each day (Monday, Tuesday, etc.) for a specific month in Java using the java.time package introduced in Java 8. In the following code snippet we will use a loop to iterate the dates in the month. The number of loop is equals to the number of days in the month.

You can run this code to get the count of each day of the week for any specific month and year. Here’s a sample code to achieve that:

package org.kodejava.datetime;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.EnumMap;
import java.util.Map;

public class DaysOfWeekInMonthWithLoop {

    public static Map<DayOfWeek, Integer> getDaysCountForMonth(int year, int month) {
        YearMonth yearMonth = YearMonth.of(year, month);
        LocalDate firstOfMonth = yearMonth.atDay(1);
        LocalDate lastOfMonth = yearMonth.atEndOfMonth();

        Map<DayOfWeek, Integer> daysCount = new EnumMap<>(DayOfWeek.class);

        for (DayOfWeek day : DayOfWeek.values()) {
            daysCount.put(day, 0);
        }

        for (LocalDate date = firstOfMonth; !date.isAfter(lastOfMonth); date = date.plusDays(1)) {
            DayOfWeek dayOfWeek = date.getDayOfWeek();
            daysCount.put(dayOfWeek, daysCount.get(dayOfWeek) + 1);
        }

        return daysCount;
    }

    public static void main(String[] args) {
        int year = 2024;
        int month = 10; // October

        Map<DayOfWeek, Integer> daysCount = getDaysCountForMonth(year, month);

        for (Map.Entry<DayOfWeek, Integer> entry : daysCount.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

Output:

MONDAY: 4
TUESDAY: 5
WEDNESDAY: 5
THURSDAY: 5
FRIDAY: 4
SATURDAY: 4
SUNDAY: 4

What we do in the code snippet above:

  1. YearMonth: Used to represent the year and month. You create an instance of YearMonth for the desired year and month.
  2. LocalDate: Represents a date (year, month, day). firstOfMonth is the first day of the month and lastOfMonth is the last day of the month.
  3. EnumMap: A specialized map for use with enum keys, which in this case are days of the week (from DayOfWeek enum).
  4. Loop through Dates: Iterate from the first to the last day of the month. For each date, get the day of the week and update the count in the map.

Another solution that we can use is to calculate the number of days using a simple mathematical calculations instead of iterating through the dates of the month.

The refined approach:

  1. Determine the first day of the month.
  2. Calculate the base number of times each day appears:
    • Each day will appear at least daysInMonth / 7 times because every 7-day week will have each day once.
    • The remainder from daysInMonth % 7 will determine how many days are left over from complete weeks, starting from the first day of the month.

Here is how we can implement it:

package org.kodejava.datetime;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.EnumMap;
import java.util.Map;

public class DaysOfWeekInMonth {

    public static Map<DayOfWeek, Integer> getDaysCountForMonth(int year, int month) {
        YearMonth yearMonth = YearMonth.of(year, month);
        LocalDate firstDayOfMonth = yearMonth.atDay(1);

        int daysInMonth = yearMonth.lengthOfMonth();
        DayOfWeek firstDayOfWeek = firstDayOfMonth.getDayOfWeek();

        Map<DayOfWeek, Integer> daysCount = new EnumMap<>(DayOfWeek.class);

        int baseCount = daysInMonth / 7;
        int extraDays = daysInMonth % 7;

        for (DayOfWeek day : DayOfWeek.values()) {
            daysCount.put(day, baseCount);
        }

        for (int i = 0; i < extraDays; i++) {
            DayOfWeek currentDay = firstDayOfWeek.plus(i);
            daysCount.put(currentDay, daysCount.get(currentDay) + 1);
        }

        return daysCount;
    }

    public static void main(String[] args) {
        int year = 2024;
        int month = 10; // October

        Map<DayOfWeek, Integer> daysCount = getDaysCountForMonth(year, month);

        for (Map.Entry<DayOfWeek, Integer> entry : daysCount.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

Output:

MONDAY: 4
TUESDAY: 5
WEDNESDAY: 5
THURSDAY: 5
FRIDAY: 4
SATURDAY: 4
SUNDAY: 4

In this approach:

  1. YearMonth: Represents the year and month.
  2. LocalDate: Determines the first day of the month.
  3. DayOfWeek: Identifies the day of the week for the first day of the month.
  4. EnumMap: Stores the count of each day of the week.
  5. Base Count and Remainder:
    • baseCount: Calculates how many whole weeks (7 days) fit in the month.
    • extraDays: Calculates the remaining days after accounting for whole weeks.
    • Initialize each count in the map to baseCount.
    • Add 1 to the first extraDays days in the week starting from firstDayOfWeek.

This approach avoids explicitly iterating over each day in the month and relies on mathematical operations to determine the count of each day of the week.

How do I get operating system process information using ProcessHandle?

Java 9 introduced the ProcessHandle API, which allows us to interact with and retrieve information about native processes. Here’s how we can use ProcessHandle to get information about operating system processes:

We can list all the processes currently running on the system and print their details:

package org.kodejava.example.lang;

import java.time.Duration;
import java.time.Instant;

public class ProcessHandleExample {
    public static void main(String[] params) {
        ProcessHandle.allProcesses()
                .forEach(process -> {
                    long pid = process.pid();
                    ProcessHandle.Info info = process.info();
                    String cmd = info.command().orElse("");
                    String[] args = info.arguments().orElse(new String[0]);
                    Instant startTime = info.startInstant().orElse(null);
                    Duration cpuUsage = info.totalCpuDuration().orElse(Duration.ZERO);

                    System.out.println("PID        = " + pid);
                    System.out.println("Command    = " + cmd);
                    System.out.println("Args       = " + String.join(" ", args));
                    System.out.println("Start Time = " + startTime);
                    System.out.println("CPU Usage  = " + cpuUsage);
                    System.out.println("------------");
                });
    }
}

If we want to get information about a specific process, we can use their process ID (PID):

package org.kodejava.example.lang;

import java.time.Duration;
import java.time.Instant;
import java.util.Optional;

public class SpecificProcessInfo {
    public static void main(String[] params) {
        // Replace with the PID of the process you want to query
        long pid = 33656;

        // Get the ProcessHandle of the specific process
        Optional<ProcessHandle> processHandle = ProcessHandle.of(pid);
        if (processHandle.isPresent()) {
            ProcessHandle process = processHandle.get();
            pid = process.pid();
            ProcessHandle.Info info = process.info();
            String cmd = info.command().orElse("");
            String[] args = info.arguments().orElse(new String[0]);
            Instant startTime = info.startInstant().orElse(null);
            Duration cpuUsage = info.totalCpuDuration().orElse(Duration.ZERO);

            System.out.println("PID        = " + pid);
            System.out.println("Command    = " + cmd);
            System.out.println("Args       = " + String.join(" ", args));
            System.out.println("Start Time = " + startTime);
            System.out.println("CPU Usage  = " + cpuUsage);
            System.out.println("------------");
        } else {
            System.out.println("No process found with PID: " + pid);
        }
    }
}

Output:

PID        = 33656
Command    = C:\Users\wayan\AppData\Local\Programs\IntelliJ IDEA Ultimate\bin\idea64.exe
Args       = 
Start Time = 2024-07-22T03:14:07.825Z
CPU Usage  = PT46M27.484375S
------------

Explanation

  • ProcessHandle.allProcesses(): returns a stream of all processes currently running on the system.
  • ProcessHandle.of(pid): returns an Optional<ProcessHandle> for the process with the given PID.
  • ProcessHandle.Info: contains information about a process, such as its command, arguments, start time, and CPU usage.
  • info.command(): returns an Optional<String> with the command used to start the process.
  • info.arguments(): returns an Optional<String[]> with the arguments passed to the process.
  • info.startInstant(): returns an Optional<Instant> with the start time of the process.
  • info.totalCpuDuration(): returns an Optional<Duration> with the total CPU time used by the process.

Using the ProcessHandle API in Java 9 and later makes it straightforward to get detailed information about operating system processes.