How do I use the UnaryOperator functional interface in Java?

The UnaryOperator functional interface in Java is a specialized form of the Function functional interface. It is used when both the input and output of a function are of the same type. This interface plays a role when we want to perform an operation on a single operand and return a result of the same type.

Key Characteristics:

  • Package: It’s part of the java.util.function package.
  • Functional method: The single abstract method in this interface is apply(T t).

Example Syntax:

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}

Usage Example:

1. Basic Example

A simple example is doubling an integer:

package org.kodejava.util.function;

import java.util.function.UnaryOperator;

public class UnaryOperatorExample {
    public static void main(String[] args) {
        // UnaryOperator to double a number
        UnaryOperator<Integer> doubleNumber = x -> x * 2;

        // Apply the operator
        Integer result = doubleNumber.apply(5);
        System.out.println(result);
        // Output: 10
    }
}

2. Using UnaryOperator with Lists

We can use UnaryOperator to modify elements in a List using replaceAll:

package org.kodejava.util.function;

import java.util.ArrayList;
import java.util.List;
import java.util.function.UnaryOperator;

public class ListOperatorExample {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Rosa");

        // UnaryOperator to convert strings to uppercase
        UnaryOperator<String> toUpperCase = String::toUpperCase;

        // Replace all elements in the list using the operator
        names.replaceAll(toUpperCase);

        // Print modified list
        System.out.println(names);
        // Output: [ALICE, BOB, ROSA]
    }
}

3. Using the identity() Method

The identity() method returns a UnaryOperator that simply returns the input as it is:

package org.kodejava.util.function;

import java.util.function.UnaryOperator;

public class UnaryOperatorIdentityExample {
    public static void main(String[] args) {
        // UnaryOperator using identity
        UnaryOperator<String> identityOperator = UnaryOperator.identity();

        // Apply the operator
        String result = identityOperator.apply("Hello World");
        System.out.println(result);
        // Output: Hello World
    }
}

4. Composing with Other Methods

We can chain UnaryOperator methods using the default methods andThen and compose:

package org.kodejava.util.function;

import java.util.function.Function;
import java.util.function.UnaryOperator;

public class ComposeExample {
    public static void main(String[] args) {
        UnaryOperator<Integer> square = x -> x * x; // Square of a number
        UnaryOperator<Integer> increment = x -> x + 1; // Increment by 1

        // Compose the operators
        Function<Integer, Integer> squareThenIncrement = square.andThen(increment);

        // Apply the composed operator
        Integer result = squareThenIncrement.apply(4);
        System.out.println(result);
        // Output: 17 (4 * 4 = 16, then 16 + 1 = 17)
    }
}

When to Use UnaryOperator

Use UnaryOperator when:
1. We have a function that takes one argument and returns a value of the same type.
2. The input and output types are guaranteed to be the same.
3. We want to manipulate lists or streams of elements of the same type.

By following these examples and understanding its purpose, the UnaryOperator becomes a handy tool while working with functional-style programming in Java.

How do I use the ToLongBiFunction functional interface in Java?

The ToLongBiFunction is a functional interface introduced in Java. It is part of the java.util.function package, and it represents a function that accepts two arguments (of generic types) and produces a long result.

The functional method in this interface is:

long applyAsLong(T t, U u);

Here’s how we can effectively use the ToLongBiFunction:

Steps to Use ToLongBiFunction:

  • Import the Interface: Ensure to import the specific interface:
   import java.util.function.ToLongBiFunction;
  • Define Behavior: Implement the applyAsLong method either through a lambda expression or anonymous class. The method takes two arguments and returns a long.
  • Use in Code: Pass it as a lambda/method reference when working with methods that require this interface.

Example Usage

Example 1: Simple Lambda Expression

package org.kodejava.util.function;

import java.util.function.ToLongBiFunction;

public class ToLongBiFunctionExample {
    public static void main(String[] args) {
        // Define a ToLongBiFunction with a lambda
        ToLongBiFunction<Integer, Integer> addAndConvertToLong = (a, b) -> (long) a + b;

        // Apply the function
        long result = addAndConvertToLong.applyAsLong(5, 10);

        // Output the result
        System.out.println("Result: " + result);
        // Output: Result: 15
    }
}

Example 2: Using Method Reference

package org.kodejava.util.function;

import java.util.function.ToLongBiFunction;

public class ToLongBiFunctionExample2 {
    public static void main(String[] args) {
        // Define the method reference
        ToLongBiFunction<String, String> stringLengthSum = ToLongBiFunctionExample2::computeLengths;

        // Apply the function
        long result = stringLengthSum.applyAsLong("Hello", "World");

        // Output the result
        System.out.println("Result: " + result);
        // Output: Result: 10
    }

    // Method to compute combined string lengths
    public static long computeLengths(String str1, String str2) {
        return (long) (str1.length() + str2.length());
    }
}

Example 3: Practical Application in Streams

We can use this interface in more complex scenarios, like computing operations in streams.

package org.kodejava.util.function;

import java.util.function.ToLongBiFunction;

public class ToLongBiFunctionWithStream {
    public static void main(String[] args) {
        // Example: Summing the lengths of two strings
        ToLongBiFunction<String, String> sumLengths = (a, b) -> a.length() + b.length();

        // Example usage
        long lengthSum = sumLengths.applyAsLong("Programming", "Java");

        System.out.println("Length Sum: " + lengthSum);
        // Output: Length Sum: 16
    }
}

Key Points of ToLongBiFunction:

  1. It is generic, meaning we can customize the types of the two input arguments (T and U).
  2. The result is always of type long.
  3. It is often useful when working with APIs such as streams that require functional-style programming.

How do I use the ToIntFunction functional interface in Java?

The ToIntFunction functional interface in Java is part of the java.util.function package and represents a function that accepts one argument and produces a int-valued result. It is a functional interface with a single abstract method int applyAsInt(T value), making it a good candidate for usage in lambda expressions or method references.

Here’s how to use the ToIntFunction:


Syntax

@FunctionalInterface
public interface ToIntFunction<T> {
    int applyAsInt(T value);
}

Example Use Cases

1. Example with a Lambda Expression

We might use ToIntFunction to transform an object to a corresponding primitive int, such as when mapping a property to an int.

package org.kodejava.util.function;

import java.util.function.ToIntFunction;

public class ToIntFunctionExample {
    public static void main(String[] args) {
        // A sample lambda expression that converts a String length to an int
        ToIntFunction<String> stringLengthFunction = str -> str.length();

        // Example usage:
        String test = "Hello, World!";
        int length = stringLengthFunction.applyAsInt(test);

        System.out.println("The length of the string \"" + test + "\" is: " + length);
    }
}

Output:

The length of the string "Hello, World!" is: 13

2. Example with Method Reference

We can also pass a method reference that produces an int from an object.

package org.kodejava.util.function;

import java.util.function.ToIntFunction;

public class ToIntFunctionExample2 {
    public static void main(String[] args) {
        // Using a method reference for String.length()
        ToIntFunction<String> stringLengthFunction = String::length;

        // Example usage:
        String test = "Functional Interface!";
        int length = stringLengthFunction.applyAsInt(test);

        System.out.println("The length of \"" + test + "\" is: " + length);
    }
}

3. Example in a Stream

ToIntFunction can be particularly useful when working with streams where we want to produce primitive int results.

package org.kodejava.util.function;

import java.util.Arrays;
import java.util.List;

public class ToIntFunctionStreamExample {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("Java", "Code", "Stream", "Example");

        // Using the mapToInt method of the Stream API
        int totalLength = words.stream()
                .mapToInt(String::length) // Use ToIntFunction
                .sum();

        System.out.println("Total length of all words: " + totalLength);
    }
}

Output:

Total length of all words: 22

Key Points:

  1. ToIntFunction is suitable when we need to transform an object into a primitive int.
  2. Use it wherever we need a concise way of defining an operation resulting in an int (e.g., extracting numeric data, calculating lengths, etc.).
  3. Works perfectly with Java’s functional programming features like lambda expressions, method references, and streams.

This makes ToIntFunction a powerful tool for reducing boilerplate code when working with primitive int values in Java programs.

How do I use the ToIntBiFunction functional interface in Java?

The ToIntBiFunction is a functional interface in Java that comes from the java.util.function package. It represents a function that accepts two arguments and produces an int as a result. This interface is useful when we need to create a lambda expression or method reference that takes in two arguments of generic types and returns an int.

Functional Method

The functional method of ToIntBiFunction is:

int applyAsInt(T t, U u);

Here:
T is the type of the first argument.
U is the type of the second argument.
– The method returns an int.

Example Use Cases

We can use ToIntBiFunction in scenarios like calculations, comparisons, or when processing two arguments to produce an int result.


Example 1: Adding Two Integer Values

package org.kodejava.util.function;

import java.util.function.ToIntBiFunction;

public class ToIntBiFunctionExample {
    public static void main(String[] args) {
        // Define a ToIntBiFunction that adds two integers
        ToIntBiFunction<Integer, Integer> add = (a, b) -> a + b;

        // Use the applyAsInt method
        int result = add.applyAsInt(5, 10);
        System.out.println("Sum: " + result);
        // Output: Sum: 15
    }
}

Example 2: Length of Concatenated Strings

package org.kodejava.util.function;

import java.util.function.ToIntBiFunction;

public class ToIntBiFunctionExample2 {
    public static void main(String[] args) {
        // Define a ToIntBiFunction that computes the length of concatenated strings
        ToIntBiFunction<String, String> concatenatedLength =
                (str1, str2) -> (str1 + str2).length();

        // Use the applyAsInt method
        int length = concatenatedLength.applyAsInt("Hello", "World");
        System.out.println("Length of concatenated string: " + length);
        // Output: 10
    }
}

Example 3: Comparing Two Numbers

package org.kodejava.util.function;

import java.util.function.ToIntBiFunction;

public class ToIntBiFunctionExample3 {
    public static void main(String[] args) {
        // Define a ToIntBiFunction that compares two integers 
        // (returns -1, 0, or 1 like Comparator)
        ToIntBiFunction<Integer, Integer> compare = (a, b) -> Integer.compare(a, b);

        // Compare two numbers
        int compareResult = compare.applyAsInt(15, 10);
        System.out.println("Comparison result: " + compareResult);
        // Output: 1 (because 15 > 10)
    }
}

Key Points:

  1. Method Signature: The applyAsInt method in ToIntBiFunction takes two arguments of types T and U, and it returns an int.
  2. Lambda-Friendly: It is commonly used with lambda expressions or method references.
  3. Generic Parameters: we can use it with any types for T and U, making it flexible for computations involving two inputs that result in an integer.

By using this functional interface, we benefit from the concise and functional programming style enabled in Java 8 and later.

How do I use the ToDoubleFunction functional interface in Java?

The ToDoubleFunction is a functional interface in Java that is part of the java.util.function package. It represents a function that takes a single input of type T and produces a double as a result. This is useful when we need to perform operations that convert objects to primitive double values, such as extracting a numeric property from an object or performing calculations.

Here’s how we can use the ToDoubleFunction interface:

Functional Method

The functional method of ToDoubleFunction<T> is:

double applyAsDouble(T value);

This method takes an input of type T and returns a double.


How to Use ToDoubleFunction

We can use it with:
1. Lambda expressions
2. Method references


Example 1: Extracting a Property from an Object

Suppose we have a class called Product with a price field, and we want to extract the price as a double using ToDoubleFunction:

package org.kodejava.util.function;

import java.util.function.ToDoubleFunction;

class TheProduct {
    private String name;
    private double price;

    public TheProduct(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public double getPrice() {
        return price;
    }
}

public class ToDoubleFunctionExample {
    public static void main(String[] args) {
        TheProduct product = new TheProduct("Laptop", 999.99);

        // Using a lambda expression
        ToDoubleFunction<TheProduct> getPrice = p -> p.getPrice();

        // Applying the function
        double price = getPrice.applyAsDouble(product);
        System.out.println("Price: " + price);

        // Using a method reference
        ToDoubleFunction<TheProduct> getPriceRef = TheProduct::getPrice;

        // Applying the function again
        double priceRef = getPriceRef.applyAsDouble(product);
        System.out.println("Price using method reference: " + priceRef);
    }
}

Output:

Price: 999.99
Price using method reference: 999.99

Example 2: Performing a Calculation

We can also use ToDoubleFunction to calculate something based on an object. For example:

package org.kodejava.util.function;

import java.util.function.ToDoubleFunction;

class Circle {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }
}

public class ToDoubleFunctionExample2 {
    public static void main(String[] args) {
        Circle circle = new Circle(5.0);

        // Lambda to calculate the area of a circle
        ToDoubleFunction<Circle> calculateArea = c -> Math.PI * Math.pow(c.getRadius(), 2);

        double area = calculateArea.applyAsDouble(circle);
        System.out.println("Circle area: " + area);
    }
}

Output:

Circle area: 78.53981633974483

Use in Streams

ToDoubleFunction is often used in streams with methods like .mapToDouble. Here’s an example:

package org.kodejava.util.function;

import java.util.ArrayList;
import java.util.List;

public class ToDoubleFunctionExample3 {
    public static void main(String[] args) {
        List<TheProduct> products = new ArrayList<>();
        products.add(new TheProduct("Book", 12.99));
        products.add(new TheProduct("Pen", 1.99));
        products.add(new TheProduct("Notebook", 4.99));

        // Calculate the total price using mapToDouble
        double totalPrice = products.stream()
                .mapToDouble(TheProduct::getPrice) // ToDoubleFunction in action
                .sum();

        System.out.println("Total price: " + totalPrice);
    }
}

Output:

Total price: 19.97

Summary

  • The ToDoubleFunction interface is commonly used to convert objects into double values.
  • Its method applyAsDouble provides a clean way to define this conversion or computation.
  • It works well with lambdas, method references, and stream operations.

How do I use the ToDoubleBiFunction functional interface in Java?

The ToDoubleBiFunction is a functional interface in Java defined in the java.util.function package. It represents a function that takes two arguments of any types and produces a double result. It can be used wherever we need to take two input arguments and return a double value.

Here is a breakdown of its functional method:

@FunctionalInterface
public interface ToDoubleBiFunction<T, U> {
    double applyAsDouble(T t, U u);
}

How to Use ToDoubleBiFunction

We can use ToDoubleBiFunction with lambda expressions or method references. Below are examples to demonstrate its usage.


Example 1: Basic Usage with Lambda Expression

This example demonstrates using a ToDoubleBiFunction to calculate the average of two integers.

package org.kodejava.util.function;

import java.util.function.ToDoubleBiFunction;

public class ToDoubleBiFunctionExample {
    public static void main(String[] args) {
        // Create a ToDoubleBiFunction to calculate the average of two integers
        ToDoubleBiFunction<Integer, Integer> average = (a, b) -> (a + b) / 2.0;

        // Apply the function
        double result = average.applyAsDouble(10, 20);

        System.out.println("The average is: " + result);
    }
}

Output:

The average is: 15.0

Example 2: Using with Custom Classes

If we have custom types as input, we can define a ToDoubleBiFunction to process their fields.

package org.kodejava.util.function;

import java.util.function.ToDoubleBiFunction;

class MyProduct {
    String name;
    double price;

    MyProduct(String name, double price) {
        this.name = name;
        this.price = price;
    }
}

public class ToDoubleBiFunctionExample2 {
    public static void main(String[] args) {
        // Create two Product objects
        MyProduct product1 = new MyProduct("Laptop", 1200.50);
        MyProduct product2 = new MyProduct("Phone", 800.30);

        // Create a ToDoubleBiFunction to find the total price of two products
        ToDoubleBiFunction<MyProduct, MyProduct> totalPrice =
                (p1, p2) -> p1.price + p2.price;

        // Apply the function
        double result = totalPrice.applyAsDouble(product1, product2);

        System.out.println("The total price is: " + result);
    }
}

Output:

The total price is: 2000.8

Example 3: Using Method References

If we have a method that matches the signature of ToDoubleBiFunction<T, U>, we can use a method reference instead of a lambda expression.

package org.kodejava.util.function;

import java.util.function.ToDoubleBiFunction;

public class ToDoubleBiFunctionExample3 {
    public static void main(String[] args) {
        // Using a static method reference
        ToDoubleBiFunction<Integer, Integer> maxFunction = ToDoubleBiFunctionExample3::findMax;

        // Apply the function
        double max = maxFunction.applyAsDouble(42, 56);

        System.out.println("The maximum value is: " + max);
    }

    // Static method to find the maximum value
    public static double findMax(int a, int b) {
        return Math.max(a, b);
    }
}

Output:

The maximum value is: 56.0

When to Use ToDoubleBiFunction

  • When we need to compute a double result from two input parameters.
  • When we want to pass a function that takes two arguments and returns a double.
  • When processing tasks with numerical computations involving two objects or values.

Keynotes:

  1. It is part of the java.util.function package and was introduced in Java 8.
  2. Since it is a functional interface, it can be used in lambda expressions and method references.
  3. It is a good choice for reducing boilerplate code by avoiding explicitly writing anonymous classes.

How do I use the Supplier functional interface in Java?

The Supplier functional interface in Java is part of the java.util.function package and is used when we need to supply or produce a result without taking any input. It is a functional interface, meaning it can be represented as a lambda expression or method reference.

The Supplier interface has a single abstract method:

T get();

This method returns an object of type T and takes no arguments.

Usage of Supplier

  1. Lambda Expression: We can use a lambda expression to define the logic for producing a result.
  2. Method Reference: If we have an existing static or instance method that matches the Supplier signature (no parameters, return a value), we can use a method reference.

Here are a few examples to demonstrate how to use Supplier:


Example 1: Basic Supplier Usage

package org.kodejava.util.function;

import java.util.function.Supplier;

public class SupplierExample {
    public static void main(String[] args) {
        // Using a Supplier to generate a string
        Supplier<String> stringSupplier = () -> "Hello, Supplier!";
        System.out.println(stringSupplier.get());
        // Output: Hello, Supplier!
    }
}

Example 2: Supplier with Random Number

package org.kodejava.util.function;

import java.util.function.Supplier;
import java.util.Random;

public class RandomNumberExample {
    public static void main(String[] args) {
        // Using a Supplier to provide a random int
        // Random number between 0-99
        Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);

        System.out.println("Random number: " + randomSupplier.get());
        System.out.println("Another random number: " + randomSupplier.get());
    }
}

Example 3: Method Reference with Supplier

package org.kodejava.util.function;

import java.util.function.Supplier;

public class SupplierMethodReferenceExample {
    public static void main(String[] args) {
        // Supplier using method reference
        Supplier<Double> piSupplier = Math::random;

        System.out.println("Random value using method reference: " + piSupplier.get());
    }
}

Example 4: Supplying an Object

package org.kodejava.util.function;

import java.util.function.Supplier;

class Person {
    String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "'}";
    }
}

public class ObjectSupplierExample {
    public static void main(String[] args) {
        // Using a Supplier to construct an object
        Supplier<Person> personSupplier = () -> new Person("Rosa");

        Person person = personSupplier.get();
        System.out.println(person);
        // Output: Person{name='Rosa'}
    }
}

Where to Use Supplier

  • Lazy Evaluation: To delay the execution of some logic until a value is needed.
  • Factories: To create new objects.
  • Caching or Computed Values: Use Supplier to generate values that are expensive to compute only when needed.

By using Supplier, we can encapsulate the logic of generating or supplying values while following the functional programming paradigm in Java.

How do I use the ObjLongConsumer functional interface in Java?

The ObjLongConsumer functional interface in Java is part of the java.util.function package and is available since Java 8. It represents an operation that accepts two input arguments: an object T and a long-valued argument, and performs some operation without returning any result. It is effectively a BiConsumer specialized for one object and one long argument.

Here’s a breakdown of how it works and how to use it:

Key Characteristics:

  1. Functional Interface:
    • It is annotated with @FunctionalInterface, meaning it contains a single abstract method to implement.
    • The method signature is:
void accept(T t, long value);
  1. Input:
    • A generic object T (the first parameter).
    • A long value (the second parameter).
  2. Output:
    • It does not return any value (similar to Consumer).
  3. Use Case:
    • Typically used in scenarios where we want to consume or process an object and a numeric value (e.g., processing an object with an associated count, index, or timestamp).

Example Usage

Here’s how we can use the ObjLongConsumer interface effectively:

package org.kodejava.util.function;

import java.util.function.ObjLongConsumer;

public class ObjLongConsumerExample {
   public static void main(String[] args) {
      // Create an ObjLongConsumer to print an object and a long value
      ObjLongConsumer<String> printDetails = (str, num) -> {
         System.out.println("String: " + str + ", Number: " + num);
      };

      // Use the ObjLongConsumer
      printDetails.accept("Example", 50);
   }
}

Output:

String: Example, Number: 50

Another Example with a Data Processor

Let’s see a more practical use case, for example, processing an object (like a product) with an associated long value (like its stock count):

package org.kodejava.util.function;

import java.util.function.ObjLongConsumer;

public class ObjLongConsumerExample2 {
   public static void main(String[] args) {
      ObjLongConsumer<Item> updateStock = (item, stock) -> {
         System.out.println("Item: " + item.name + ", Stock: " + stock);
      };

      Item apple = new Item("Apple");
      Item banana = new Item("Banana");

      // Update the stock of products
      updateStock.accept(apple, 100L);
      updateStock.accept(banana, 50L);
   }
}

class Item {
   String name;

   public Item(String name) {
      this.name = name;
   }
}

Output:

Item: Apple, Stock: 100
Item: Banana, Stock: 50

Real-World Use Cases

  1. Logging operations:
    • Log details of an event and a timestamp.
  2. Streams and Iteration:
    • It can be used in conjunction with streams where we need to process both an object and a primitive value like a long.

For example, using a loop with an index:

package org.kodejava.util.function;

import java.util.function.ObjLongConsumer;
import java.util.stream.IntStream;

public class ObjLongConsumerWithStreams {
   public static void main(String[] args) {
      ObjLongConsumer<String> indexedPrinter = (value, index) -> {
         System.out.println("Index: " + index + ", Value: " + value);
      };

      // Example: Using a range with an array
      String[] items = {"Apple", "Banana", "Cherry"};
      IntStream.range(0, items.length).forEach(i -> indexedPrinter.accept(items[i], i));
   }
}

Output:

Index: 0, Value: Apple
Index: 1, Value: Banana
Index: 2, Value: Cherry

Summary

  1. Use ObjLongConsumer when we need a functional interface that processes a combination of an object and a long value without returning a result.
  2. It is particularly useful for processing lists, objects with associated numeric properties, or items in streams with their indices.
  3. The accept method is where we specify what happens with the inputs.

This makes ObjLongConsumer a simple yet powerful tool for functional programming in Java!

How do I use the ObjIntConsumer functional interface in Java?

The ObjIntConsumer is a functional interface in Java, introduced in Java 8, as part of the java.util.function package. It represents an operation that takes an object (T) and an int as input arguments and returns no result. It’s essentially a BiConsumer that specifically takes an int as one of the parameters.

Here is a breakdown of how we can use the ObjIntConsumer interface:


Functional Interface Definition

@FunctionalInterface
public interface ObjIntConsumer<T> {
    void accept(T t, int value);
}

Key Features:

  1. The accept method is the only abstract method in this interface. It accepts two parameters:
    • T t (an object of any type)
    • int value (a primitive integer)
  2. Unlike BiConsumer<T, U>, this interface avoids boxing for the second parameter by working directly with a primitive int.

Example Usage:

1. Basic Example:

We can use ObjIntConsumer as a lambda expression or assign it to handle specific functionality.

package org.kodejava.util.function;

import java.util.function.ObjIntConsumer;

public class ObjIntConsumerExample {

   public static void main(String[] args) {
      // Create an ObjIntConsumer
      ObjIntConsumer<String> printNTimes = (str, count) -> {
         for (int i = 0; i < count; i++) {
            System.out.println(str);
         }
      };

      // Use the ObjIntConsumer
      printNTimes.accept("Hello, World!", 3);
   }
}

Output:

Hello, World!
Hello, World!
Hello, World!

2. Processing a List With Indices:

We can use it to perform an operation on a list, with the int parameter as the index.

package org.kodejava.util.function;

import java.util.List;
import java.util.function.ObjIntConsumer;

public class ObjIntConsumerWithListExample3 {

   public static void main(String[] args) {
      List<String> names = List.of("Alice", "Bob", "Charlie");

      // Create an ObjIntConsumer
      ObjIntConsumer<List<String>> printNameWithIndex = (list, index) ->
              System.out.println("Index: " + index + ", Name: " + list.get(index));

      // Apply the ObjIntConsumer on the list
      for (int i = 0; i < names.size(); i++) {
         printNameWithIndex.accept(names, i);
      }
   }
}

Output:

Index: 0, Name: Alice
Index: 1, Name: Bob
Index: 2, Name: Charlie

3. Using With Custom Objects:

We can apply ObjIntConsumer with custom objects. For instance:

package org.kodejava.util.function;

import java.util.function.ObjIntConsumer;

public class ObjIntConsumerCustomObjectExample4 {

   public static void main(String[] args) {
      Product product = new Product("Laptop", 1000);

      // Create an ObjIntConsumer
      ObjIntConsumer<Product> applyDiscount = (prod, discount) -> prod.applyDiscount(discount);

      // Apply a 15% discount
      applyDiscount.accept(product, 15);

      // Print updated product details
      System.out.println(product);
   }
}

class Product {
   private String name;
   private double price;

   public Product(String name, double price) {
      this.name = name;
      this.price = price;
   }

   public void applyDiscount(int percentage) {
      this.price -= (this.price * percentage / 100.0);
   }

   @Override
   public String toString() {
      return "Product{name='" + name + "', price=" + price + '}';
   }
}

Output:

Product{name='Laptop', price=850.0}

Key Use Cases

  1. Index-Based Operations: Applying operations that depend on both an object and an index or count.
  2. Side Effects: Performing actions like printing or logging inside lambdas.
  3. Custom Logic: Executing custom logic on objects with an additional int parameter, e.g., percentages, counters, etc.

The ObjIntConsumer is a lightweight and specialized functional interface that simplifies defining operations combining objects and primitive int parameters, without incurring boxing overhead!

How do I use the ObjDoubleConsumer functional interface in Java?

In Java, the ObjDoubleConsumer is part of the java.util.function package, and it represents a functional interface. It takes two arguments:

  1. An object of type T
  2. A double-valued argument

The functional method of this interface is accept(T t, double value), which performs an operation that accepts these two parameters but does not return any result (void).

Steps to Use ObjDoubleConsumer

  1. Use as a Lambda Expression: We can implement the accept method using a lambda.
  2. Use for Side Effects: This interface is typically used for operations that perform side effects rather than computing a result (e.g., logging, modifying an object, etc.).

Example 1: Using ObjDoubleConsumer with a Lambda

Here’s a basic example that demonstrates logging an object and a double value.

package org.kodejava.util.function;

import java.util.function.ObjDoubleConsumer;

public class ObjDoubleConsumerExample {
    public static void main(String[] args) {
        ObjDoubleConsumer<String> logger = (str, value) -> {
            System.out.println("The provided string: " + str);
            System.out.println("The associated double value: " + value);
        };

        // Using the ObjDoubleConsumer
        logger.accept("Temperature", 36.5);
    }
}

Output:

The provided string: Temperature
The associated double value: 36.5

Example 2: Modifying an Object Using ObjDoubleConsumer

Here’s an example of modifying an object field using an ObjDoubleConsumer.

package org.kodejava.util.function;

import java.util.function.ObjDoubleConsumer;

public class ObjDoubleConsumerExample2 {
    public static void main(String[] args) {
        ObjDoubleConsumer<Box> updateWeight = (box, weight) -> box.weight = weight;

        // Create a Box object
        Box box = new Box("Package1", 5.0);
        System.out.println("Before: " + box);

        // Update the weight using ObjDoubleConsumer
        updateWeight.accept(box, 10.5);
        System.out.println("After: " + box);
    }
}

class Box {
    String label;
    double weight;

    public Box(String label, double weight) {
        this.label = label;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Box[label=" + label + ", weight=" + weight + "]";
    }
}

Output:

Before: Box[label=Package1, weight=5.0]
After: Box[label=Package1, weight=10.5]

Example 3: Using ObjDoubleConsumer with Streams

Sometimes, ObjDoubleConsumer works well with streams. For instance, it is useful when working with an operation based on an object and a primitive value (such as logging or computations).

package org.kodejava.util.function;

import java.util.function.ObjDoubleConsumer;
import java.util.stream.DoubleStream;

public class ObjDoubleConsumerStreamExample3 {
    public static void main(String[] args) {
        DoubleStream doubleStream = DoubleStream.of(1.5, 2.7, 3.8);

        // ObjDoubleConsumer to print values with a prefix
        ObjDoubleConsumer<String> printer =
                (prefix, value) -> System.out.println(prefix + ": " + value);

        // Use it with a stream
        doubleStream.forEach(value -> printer.accept("Value", value));
    }
}

Output:

Value: 1.5
Value: 2.7
Value: 3.8

Key Points:

  • Functional Method: accept(T t, double value) is the functional method.
  • Target Use: Designed for operations that take two arguments (T and double) and produce side effects.
  • Common Usage: Modifying existing objects, logging two parameters, or iterating over collections of objects and associated double values.

By following these use cases, we can effectively incorporate ObjDoubleConsumer wherever applicable!