This set of 21 Java method exercises goes well beyond writing a basic function, walking through the patterns that show up constantly in real Java codebases.
You’ll practice method overloading, variable-length arguments (varargs), classic recursion , and Java’s pass-by-value semantics for primitives versus object references. Later exercises cover the fluent interface (method chaining) pattern, encapsulating logic in private helper methods, and passing behavior into a method using functional interfaces and lambda expressions.
Each exercise includes a Problem Statement, Purpose, Hint, and a Solution with Explanation that breaks down exactly how and why the code works.
- Also, See: Java Exercises with over 20+ topic-wise sets and 575+ coding questions to practice.
- Practice questions using our Online Java Compiler
+ Table of Contents (21 Exercises)
Table of contents
- Exercise 1: Circle Area Calculator
- Exercise 2: The Overloaded Adder
- Exercise 3: Multi-Shape Area Calculator
- Exercise 4: Flexible Print Details
- Exercise 5: Array Searcher
- Exercise 6: Absolute Value Replication
- Exercise 7: Dynamic Summation
- Exercise 8: String Concat with Separator
- Exercise 9: Safe Minimum Finder
- Exercise 10: Dynamic Average Calculator
- Exercise 11: Shopping Invoice Logger
- Exercise 12: Factorial Finder
- Exercise 13: Fibonacci Sequence Decoder
- Exercise 14: Sum of Digits
- Exercise 15: Power Calculation
- Exercise 16: Recursive Array Summation
- Exercise 17: Pass-by-Value Proof
- Exercise 18: Fluent Interface / Method Chaining
- Exercise 19: Helper Method Encapsulation
- Exercise 20: In-Place Array Transformer
- Exercise 21: Basic Functional Method
Exercise 1: Circle Area Calculator
Problem Statement: Write a method double calculateArea(double radius) that calculates and returns the area of a circle. As a bonus, handle negative radius inputs by returning -1.0.
Purpose: This exercise helps you practice writing a method with a return value and basic input validation, foundational skills for building reusable utility methods.
Given Input: calculateArea(5.0)
Expected Output: Area = 78.53981633974483
▼ Hint
- Define the method with a
doubleparameter for radius and adoublereturn type. - Check if the radius is negative first; if so, return
-1.0immediately. - Otherwise, calculate the area using the formula π × radius².
- Use
Math.PIfor an accurate value of pi.
▼ Solution & Explanation
Explanation:
if (radius < 0): Guards against invalid input before doing any calculation, returning-1.0as a sentinel value for errors.Math.PI * radius * radius: Applies the standard circle area formula using Java's built-in constant for pi.- Return type
double: Ensures the method can return a precise decimal value rather than being rounded to an integer. - Alternative: You could use
Math.pow(radius, 2)instead ofradius * radius, though direct multiplication is generally faster for a simple square.
Exercise 2: The Overloaded Adder
Problem Statement: Write three overloaded methods named add(): int add(int a, int b), int add(int a, int b, int c), and double add(double a, double b).
Purpose: This exercise helps you practice method overloading, understanding how Java distinguishes methods based on parameter types and count.
Given Input: add(2, 3), add(2, 3, 4), add(2.5, 3.5)
Expected Output:
add(2, 3) = 5 add(2, 3, 4) = 9 add(2.5, 3.5) = 6.0
▼ Hint
- Define multiple methods with the same name but different parameter lists.
- Java distinguishes overloaded methods by the number and/or types of parameters, not by return type alone.
- The two-integer version and three-integer version differ by parameter count.
- The double version differs by parameter type, even though its parameter count matches the two-integer version.
▼ Solution & Explanation
Explanation:
add(int a, int b)andadd(int a, int b, int c): Differ in the number of parameters, so Java treats them as distinct methods.add(double a, double b): Differs in parameter type from the two-integer version, letting Java select the correct overload based on the argument types passed in.- Compile-time resolution: Java determines which overload to call at compile time based on the arguments' types, not at runtime.
- Alternative: You could achieve similar flexibility with a single method using
Object...varargs and manual type checking, but overloading is clearer and type-safe.
Exercise 3: Multi-Shape Area Calculator
Problem Statement: Create overloaded methods named computeArea() to handle different shapes: double computeArea(double radius) for a circle, double computeArea(double length, double width) for a rectangle, and double computeArea(double base, double height, boolean isTriangle) for a triangle.
Purpose: This exercise helps you practice designing overloaded methods that share a name but serve different geometric purposes, distinguished by their parameter signatures.
Given Input: computeArea(5.0), computeArea(4.0, 6.0), computeArea(4.0, 6.0, true)
Expected Output:
Circle Area = 78.53981633974483 Rectangle Area = 24.0 Triangle Area = 12.0
▼ Hint
- Define a version that takes a single
doublefor the circle's radius. - Define a version that takes two
doublevalues for the rectangle's length and width. - Define a version that takes two
doublevalues and abooleanflag for the triangle, even though the flag isn't strictly needed for the calculation. - Java will select the correct method automatically based on how many arguments are passed and their types.
▼ Solution & Explanation
Explanation:
computeArea(double radius): Matches calls with exactly onedoubleargument, calculating a circle's area.computeArea(double length, double width): Matches calls with twodoublearguments, calculating a rectangle's area.computeArea(double base, double height, boolean isTriangle): Matches calls with two doubles and a boolean, calculating a triangle's area using the base-height formula.- Alternative: You could rename each method distinctly, like
circleArea()andrectangleArea(), for extra clarity, but overloading keeps a consistent API name for related operations.
Exercise 4: Flexible Print Details
Problem Statement: Create a series of printDetails() methods: one accepting only a name (String), one accepting a name and an age (String, int), and one accepting a name, age, and city (String, int, String). Each should print a cleanly formatted summary.
Purpose: This exercise helps you practice overloading with an increasing number of parameters, a common pattern for building flexible utility or logging methods.
Given Input: printDetails("Alice"), printDetails("Bob", 25), printDetails("Charlie", 30, "New York")
Expected Output:
Name: Alice Name: Bob, Age: 25 Name: Charlie, Age: 30, City: New York
▼ Hint
- Write the simplest overload first, accepting only a name and printing it.
- Write a second overload accepting a name and an age, printing both together.
- Write a third overload accepting a name, age, and city, printing all three.
- Each version should build its own formatted output rather than calling the others.
▼ Solution & Explanation
Explanation:
printDetails(String name): Handles calls with only a name, producing the shortest summary.printDetails(String name, int age): Handles calls with a name and age, adding the age to the printed output.printDetails(String name, int age, String city): Handles calls with all three pieces of information, producing the fullest summary.- Alternative: You could have the shorter overloads call the longer one with default values, like
printDetails(name, 0, "Unknown"), which reduces duplication but requires meaningful defaults.
Exercise 5: Array Searcher
Problem Statement: Write two overloaded search() methods. One searches for an integer target inside an int[] array; the other searches for a String target inside a String[] array. Both should return the index of the found element, or -1 if not found.
Purpose: This exercise helps you practice overloading based on array element type, a pattern used in generic-feeling utility methods before generics are introduced.
Given Input: search(new int[]{10, 20, 30, 40}, 30), search(new String[]{"apple", "banana", "cherry"}, "banana")
Expected Output:
Index of 30 = 2 Index of "banana" = 1
▼ Hint
- Write one version of
search()that accepts anint[]array and aninttarget. - Write a second version that accepts a
String[]array and aStringtarget. - Loop through the array in each version, comparing each element to the target.
- Return the index immediately upon a match, or
-1if the loop finishes without finding one.
▼ Solution & Explanation
Explanation:
search(int[] arr, int target): Uses==to compare primitive int values directly, since primitives can be compared with equality operators.search(String[] arr, String target): Uses.equals()instead of==to compare String content rather than object references.return i/return -1: Returns the matching index immediately, or -1 once the loop completes without a match.- Alternative: You could use
Arrays.asList(arr).indexOf(target)for the String version to leverage a built-in list search, though it doesn't work directly for primitiveint[]arrays.
Exercise 6: Absolute Value Replication
Problem Statement: Create your own version of Math.abs(). Overload a method named absoluteValue() to accept and process int, double, and long types.
Purpose: This exercise helps you practice overloading across primitive numeric types, useful for understanding how Java resolves overloads for related but distinct types.
Given Input: absoluteValue(-5), absoluteValue(-3.14), absoluteValue(-100000000000L)
Expected Output:
absoluteValue(-5) = 5 absoluteValue(-3.14) = 3.14 absoluteValue(-100000000000) = 100000000000
▼ Hint
- Write a version that accepts an
intand returns anint. - Write a version that accepts a
doubleand returns adouble. - Write a version that accepts a
longand returns along. - In each version, check if the value is negative and negate it if so; otherwise return it unchanged.
▼ Solution & Explanation
Explanation:
value < 0 ? -value : value: Uses a ternary expression to negate the value only if it's negative, returning it unchanged otherwise.- Separate
int,double, andlongoverloads: Ensures each numeric type is handled with its own precision and range, without relying on implicit widening or narrowing conversions. - Method resolution: Java automatically picks the overload matching the argument's exact type, or the closest compatible type if no exact match exists.
- Alternative: You could write a single method using
doublefor all inputs, but that would lose precision for largelongvalues and force unnecessary type conversions.
Exercise 7: Dynamic Summation
Problem Statement: Create a method int sumAll(int... numbers) that accepts any quantity of integers (including zero) and returns their total sum.
Purpose: This exercise helps you practice varargs syntax, useful for writing methods that accept a flexible number of arguments without overloading.
Given Input: sumAll(1, 2, 3, 4, 5)
Expected Output: Sum = 15
▼ Hint
- Declare the parameter using the
int...syntax, which allows zero or more integers to be passed. - Inside the method, treat the parameter as a regular
int[]array. - Loop through the array and accumulate a running total.
- Return the total after the loop completes, which will be zero if no arguments were passed.
▼ Solution & Explanation
Explanation:
int... numbers: Declares a varargs parameter, letting the caller pass any number ofintarguments, which Java packages into an array.for (int num : numbers): Iterates over the array just like any other array, since varargs behave as arrays inside the method body.total += num: Accumulates the sum across all provided arguments.- Alternative: You could use
Arrays.stream(numbers).sum()for a more concise one-liner, though the loop makes the accumulation logic explicit.
Exercise 8: String Concat with Separator
Problem Statement: Write a method String joinStrings(String separator, String... words) that merges all passed words together, separated by the designated separator string.
Purpose: This exercise helps you practice combining a fixed parameter with a varargs parameter, a common pattern for methods needing at least one required argument alongside flexible ones.
Given Input: joinStrings("-", "Java", "is", "fun")
Expected Output: Result = Java-is-fun
▼ Hint
- Place the fixed separator parameter before the varargs parameter, since varargs must always come last.
- Use a
StringBuilderto build the result incrementally. - Append each word followed by the separator, except after the very last word.
- Handle the case of zero words gracefully by returning an empty string.
▼ Solution & Explanation
Explanation:
String separator, String... words: Places the required separator argument before the varargs parameter, which Java requires since varargs must be the last parameter.if (i != words.length - 1): Avoids appending a trailing separator after the final word.result.toString(): Converts the accumulatedStringBuildercontent into the final joined string.- Alternative: You could use
String.join(separator, words)directly, since it accepts a varargs array too, but writing it manually shows how the built-in method works internally.
Exercise 9: Safe Minimum Finder
Problem Statement: Write a method int findMin(int first, int... rest) that guarantees at least one integer argument is passed to prevent runtime exceptions, returning the smallest value among all inputs.
Purpose: This exercise helps you practice combining a required parameter with varargs to enforce a minimum argument count at compile time.
Given Input: findMin(8, 3, 12, 5, 1)
Expected Output: Minimum = 1
▼ Hint
- Require the first argument as a normal
intparameter, separate from the varargs. - This guarantees the caller must supply at least one value, since the compiler enforces the required parameter.
- Start your running minimum using the required first argument.
- Loop through the varargs array and update the minimum whenever a smaller value is found.
▼ Solution & Explanation
Explanation:
int first, int... rest: Splits the arguments into one required value and any number of additional values, guaranteeing at least one argument overall.int min = first: Initializes the running minimum using the guaranteed first argument, avoiding the need to check for an empty array.num < min: Updates the minimum whenever a smaller value is encountered while scanning the remaining arguments.- Alternative: You could accept a plain
int... valuesarray without a required first parameter, but then you would need extra logic to handle the case of zero arguments.
Exercise 10: Dynamic Average Calculator
Problem Statement: Create a method double calculateAverage(double... values) that computes the average of the provided numbers. Return 0.0 if no arguments are passed.
Purpose: This exercise helps you practice handling the empty-input edge case with varargs, an important defensive programming habit.
Given Input: calculateAverage(4.0, 8.0, 15.0, 16.0)
Expected Output: Average = 10.75
▼ Hint
- Check if the varargs array has a length of zero first, and return
0.0immediately in that case to avoid dividing by zero. - Otherwise, loop through the array and accumulate a running total.
- Divide the total by the number of values to compute the average.
- Return the resulting
doublevalue.
▼ Solution & Explanation
Explanation:
values.length == 0: Guards against dividing by zero when no arguments are passed, returning0.0as a safe default.for (double value : values): Iterates over the varargs array to accumulate the total sum of all provided values.total / values.length: Divides the sum by the count of values to compute the average.- Alternative: You could use
Arrays.stream(values).average().orElse(0.0), which handles the empty case built in, though the manual loop is clearer for beginners.
Exercise 11: Shopping Invoice Logger
Problem Statement: Write a method void logItems(String storeName, String... items) that prints out a stylized receipt header using the store name, followed by a numbered list of all items passed to the varargs parameter.
Purpose: This exercise helps you practice using varargs for real-world formatted output, useful for building lightweight reporting or logging utilities.
Given Input: logItems("Java Mart", "Bread", "Milk", "Eggs")
Expected Output:
=== Java Mart === 1. Bread 2. Milk 3. Eggs
▼ Hint
- Print a formatted header line first, incorporating the store name.
- Loop through the varargs items array using an index-based loop so you can number each entry.
- Print each item with its position number, starting from 1 instead of 0.
- Since the method returns
void, print directly instead of building a return value.
▼ Solution & Explanation
Explanation:
String storeName, String... items: Requires a store name while allowing any number of item names to follow."=== " + storeName + " ===": Prints a simple stylized header framing the store name.(i + 1) + ". " + items[i]: Numbers each item starting from 1, which reads more naturally than a zero-based index.- Alternative: You could use a for-each loop with a separate counter variable instead of an index-based loop, though the index-based version is more concise here.
Exercise 12: Factorial Finder
Problem Statement: Write a recursive method long factorial(int n) that returns the factorial of n.
Purpose: This exercise helps you practice identifying a base case and a recursive case, the two building blocks of any recursive method.
Given Input: factorial(5)
Expected Output: Factorial = 120
▼ Hint
- Identify the base case: the factorial of 0 or 1 is 1.
- For the recursive case, multiply
nby the factorial ofn - 1. - Each recursive call should move closer to the base case by decreasing
n. - Use
longas the return type to accommodate larger factorial values that would overflow anint.
▼ Solution & Explanation
Explanation:
if (n <= 1): Defines the base case, stopping the recursion oncenreaches 0 or 1.n * factorial(n - 1): Defines the recursive case, breaking the problem into a smaller version of itself.- Return type
long: Prevents overflow for larger inputs, since factorials grow very quickly. - Alternative: You could compute the factorial iteratively with a
forloop, which avoids the overhead of repeated method calls but doesn't demonstrate recursion.
Exercise 13: Fibonacci Sequence Decoder
Problem Statement: Write a recursive method int fibonacci(int n) that calculates the n-th number in the Fibonacci sequence.
Purpose: This exercise helps you practice recursion with two base cases and two recursive branches, a pattern common to many divide-and-conquer problems.
Given Input: fibonacci(7)
Expected Output: Fibonacci(7) = 13
▼ Hint
- Identify the two base cases:
fibonacci(0)returns 0 andfibonacci(1)returns 1. - For the recursive case, return the sum of
fibonacci(n - 1)andfibonacci(n - 2). - Each recursive call branches into two further calls, forming a tree of calls.
- This straightforward approach recalculates values many times, which is fine for small inputs but inefficient for large ones.
▼ Solution & Explanation
Explanation:
if (n == 0)/if (n == 1): Defines the two base cases needed to anchor the recursion, since each Fibonacci number depends on the two before it.fibonacci(n - 1) + fibonacci(n - 2): Defines the recursive case, combining the two preceding Fibonacci numbers.- Call tree: Each call to
fibonacci(n)spawns two more calls, so the number of calls grows exponentially withn. - Alternative: You could use memoization with a
Map<Integer, Integer>to cache previously computed values, dramatically reducing redundant calculations for larger inputs.
Exercise 14: Sum of Digits
Problem Statement: Write a recursive method int sumDigits(int n) that takes an integer and sums its individual digits (e.g., passing 1234 returns 1 + 2 + 3 + 4 = 10).
Purpose: This exercise helps you practice using modulus and division together to peel digits off a number recursively.
Given Input: sumDigits(1234)
Expected Output: Sum of Digits = 10
▼ Hint
- Identify the base case: when
nis 0, return 0 since there are no more digits to add. - For the recursive case, add the last digit of
n(using the modulus operator) to the result of the recursive call on the remaining digits. - Remove the last digit from
nby dividing it by 10 for the recursive call. - This approach processes the number one digit at a time, from right to left.
▼ Solution & Explanation
Explanation:
if (n == 0): Defines the base case, stopping the recursion once all digits have been processed.n % 10: Extracts the last digit of the current number using the modulus operator.n / 10: Removes the last digit using integer division, preparing the smaller sub-problem for the next recursive call.- Alternative: You could convert the number to a string and iterate over its characters, but the arithmetic approach avoids unnecessary type conversion.
Exercise 15: Power Calculation
Problem Statement: Create a recursive method int power(int base, int exponent) that calculates base raised to exponent, without using Java's built-in Math.pow().
Purpose: This exercise helps you practice recursion where one parameter counts down toward the base case while another stays fixed.
Given Input: power(2, 10)
Expected Output: Result = 1024
▼ Hint
- Identify the base case: any base raised to the power of 0 equals 1.
- For the recursive case, multiply the base by the result of raising it to one lower exponent.
- Each recursive call reduces the exponent by 1, moving toward the base case.
- Assume a non-negative exponent for this exercise to keep the base case simple.
▼ Solution & Explanation
Explanation:
if (exponent == 0): Defines the base case, since any number raised to the power of 0 is 1.base * power(base, exponent - 1): Defines the recursive case, multiplying the base by the result of a smaller power calculation.exponent - 1: Reduces the exponent with each call, guaranteeing the recursion eventually reaches the base case.- Alternative: You could use a divide-and-conquer approach that halves the exponent each call (exponentiation by squaring), which runs in logarithmic time instead of linear time.
Exercise 16: Recursive Array Summation
Problem Statement: Write a recursive method int sumArray(int[] arr, int index) that totals all elements in an integer array by processing elements from the specified index to the end of the array.
Purpose: This exercise helps you practice using an index parameter to track recursive progress through an array without modifying the array itself.
Given Input: sumArray(new int[]{4, 8, 15, 16, 23, 42}, 0)
Expected Output: Sum = 108
▼ Hint
- Identify the base case: when the index reaches the length of the array, there's nothing left to add, so return 0.
- For the recursive case, add the element at the current index to the result of summing the rest of the array.
- Increment the index by 1 with each recursive call to move toward the end of the array.
- The array itself doesn't need to be modified, only the index parameter changes between calls.
▼ Solution & Explanation
Explanation:
if (index == arr.length): Defines the base case, stopping the recursion once every element has been processed.arr[index] + sumArray(arr, index + 1): Defines the recursive case, adding the current element to the sum of the remaining elements.index + 1: Advances the index with each call, ensuring the recursion progresses toward the base case.- Alternative: You could sum the array from the end backward instead of the front, though starting at the beginning reads more naturally.
Exercise 17: Pass-by-Value Proof
Problem Statement: Create a method void modifyValues(int primitive, int[] reference). Inside, modify both inputs (reassign the primitive and alter an index of the array). Call this from your main method to observe and explain why the original array changed, but the original primitive did not.
Purpose: This exercise helps you practice understanding Java's pass-by-value semantics, and how they behave differently for primitives versus object references like arrays.
Given Input: int number = 10; int[] arr = {1, 2, 3}; modifyValues(number, arr);
Expected Output:
Before: number = 10, arr[0] = 1 After: number = 10, arr[0] = 99
▼ Hint
- Inside the method, reassign the primitive parameter to a new value and change one element of the array parameter.
- Print the primitive and array values in
mainboth before and after calling the method. - Remember that Java is always pass-by-value, but for arrays, the value being passed is a reference to the same underlying array object.
- Reassigning the primitive parameter only changes the local copy inside the method, while modifying an array index changes the shared object itself.
▼ Solution & Explanation
Explanation:
primitive = 999: Only reassigns the local copy of the primitive inside the method; the original variable inmainis untouched, since primitives are passed by value.reference[0] = 99: Modifies the array object itself, which both the caller and the method refer to through their own copies of the same reference.- Pass-by-value for references: Java always passes a copy of the reference variable, but that copy still points to the same object in memory, so mutations through it are visible outside the method.
- Key takeaway: Reassigning a reference parameter to a brand new array, like
reference = new int[]{...}, would not affect the caller's array, but mutating the existing array's contents does.
Exercise 18: Fluent Interface / Method Chaining
Problem Statement: Design a simple Hero class with fields like name, health, and weapon. Implement setter methods (setName(), setHealth()) that return this, allowing you to instantiate and configure an object in a single line: Hero player = new Hero().setName("Arthur").setHealth(100);
Purpose: This exercise helps you practice the fluent interface pattern, a common technique for writing readable, chainable configuration code.
Given Input: Hero player = new Hero().setName("Arthur").setHealth(100);
Expected Output: Hero{name='Arthur', health=100, weapon='null'}
▼ Hint
- Define private fields for name, health, and weapon inside the
Heroclass. - Have each setter method perform its assignment and then return
this, referring to the current object instance. - Returning
thisallows the next method call to be chained directly onto the result of the previous one. - Add a
toString()method so you can easily print the final configured object.
▼ Solution & Explanation
Explanation:
return this: Returns a reference to the current object at the end of each setter, which is what enables chaining.new Hero().setName("Arthur").setHealth(100): Each method call in the chain operates on and returns the sameHeroinstance, so the configuration accumulates across the chain.- Unset
weaponfield: RemainsnullsincesetWeapon()was never called in this example, which thetoString()output reflects. - Alternative: You could use a separate Builder class instead of chaining setters directly on
Hero, which better separates construction logic from the object itself for more complex classes.
Exercise 19: Helper Method Encapsulation
Problem Statement: Write a public method void processUsername(String username). Inside, use a hidden private helper method boolean isValid(String user) to run regex validation checks before printing a success or failure message.
Purpose: This exercise helps you practice encapsulating implementation details in private helper methods, keeping the public interface of a class clean and focused.
Given Input: processUsername("valid_user1"), processUsername("in valid!")
Expected Output:
valid_user1 is a valid username. in valid! is not a valid username.
▼ Hint
- Define a private helper method that returns true or false based on a regex pattern, such as only allowing letters, digits, and underscores.
- Keep the regex validation logic entirely inside the private method, hidden from outside callers.
- In the public method, call the private helper and branch on its result to print the appropriate message.
- This separation keeps the public method focused on messaging while the private method focuses on validation.
▼ Solution & Explanation
Explanation:
private boolean isValid(String user): Restricts this helper method to internal use within the class, hiding the validation details from external callers.user.matches("[a-zA-Z0-9_]+"): Checks that the entire username consists only of letters, digits, and underscores using a regular expression.if (isValid(username)): The public method delegates the validation decision to the helper, keeping its own logic focused on choosing which message to print.- Alternative: You could inline the regex check directly inside
processUsername(), but extracting it into a private helper keeps the public method more readable and the validation logic reusable.
Exercise 20: In-Place Array Transformer
Problem Statement: Write a method void doubleElements(int[] nums) that doubles every integer inside the array in-place. This exercise tests your understanding of mutable reference pass-by-value mechanics.
Purpose: This exercise helps you practice modifying an array's contents directly through its reference, without needing to return a new array.
Given Input: int[] nums = {1, 2, 3, 4}; doubleElements(nums);
Expected Output:
Before: [1, 2, 3, 4] After: [2, 4, 6, 8]
▼ Hint
- Loop through the array using an index-based loop so each element can be reassigned.
- Multiply each element by 2 and assign the result back to the same index.
- Since arrays are passed by reference value, modifying elements inside the method changes the original array the caller sees.
- Use
Arrays.toString()to conveniently print the array's contents before and after the change.
▼ Solution & Explanation
Explanation:
nums[i] = nums[i] * 2: Overwrites each element with double its original value, modifying the array's contents directly.- Return type
void: The method doesn't need to return anything, since the changes are made directly to the array object the caller already holds a reference to. Arrays.toString(nums): Provides a readable string representation of the array's contents for printing.- Alternative: You could return a brand new array with doubled values instead of modifying in place, which avoids side effects but requires the caller to reassign the result.
Exercise 21: Basic Functional Method
Problem Statement: Create a method int operate(int a, int b, java.util.function.BiFunction<Integer, Integer, Integer> operation) that executes an abstract mathematical operation on two integers. Call it from your main class using lambda expressions for addition, subtraction, and multiplication.
Purpose: This exercise helps you practice passing behavior as an argument using functional interfaces and lambda expressions, a core idea in functional-style Java programming.
Given Input: operate(5, 3, (x, y) -> x + y), operate(5, 3, (x, y) -> x - y), operate(5, 3, (x, y) -> x * y)
Expected Output:
Addition = 8 Subtraction = 2 Multiplication = 15
▼ Hint
- Define the method to accept two integers and a
BiFunction<Integer, Integer, Integer>representing the operation to perform. - Inside the method, call
operation.apply(a, b)to execute whichever logic was passed in. - At the call site, pass different lambda expressions to perform different operations without writing separate methods for each.
- This approach lets the caller decide the behavior while the method handles the structure.
▼ Solution & Explanation
Explanation:
BiFunction<Integer, Integer, Integer> operation: Represents a function that takes two Integer inputs and produces an Integer result, allowing behavior to be passed as an argument.operation.apply(a, b): Executes whichever operation was supplied at the call site, without the method itself knowing the specific logic in advance.(x, y) -> x + y: A lambda expression that implements theBiFunctioninterface inline, defining addition without a separate named method.- Alternative: You could define named methods for each operation and pass method references, like
Integer::sum, instead of writing lambda expressions directly.

Leave a Reply