zhaopinxinle.com

Enhancing Code Clarity with Reduction in Java and Kotlin

Written on

Chapter 1: Understanding Reduction

Programming with a functional approach enhances the declarative nature and readability of your code. A vital concept in this realm is reduction. When combined with mapping techniques, it offers innovative ways to manipulate and extract data, streamlining your programming experience and easing code maintenance. This article delves into various methods of using reduction and mapReduce in both Java and Kotlin, with the hope of addressing common questions on the topic.

This video provides a clear explanation of reducing in Kotlin collections:

Section 1.1: Simple Reduction in Java

In Java, the simplest form of the reduce function is:

Optional<T> reduce(BinaryOperator<T> accumulator)

This function allows for an operation to be performed on each stream element, collecting results as it goes. Upon invocation, the accumulator.apply(T first, T second) method uses the outcome of the previous operation as the first argument and the current element as the second, with the return value serving as input for the next iteration. The final result from the last iteration becomes the overall return value.

Here’s a practical example:

int addNumbers(final List<Integer> ints) {

return ints.stream()

.reduce((acc, curr) -> acc + curr)

.orElse(0);

}

In this example, the initial value for acc is derived from the first stream element, while curr takes on the next element in the iteration.

The following table illustrates the iterations when using List.of(1, 2, 3, 4, 5):

iteration | acc | curr | return value |
1 | 1 | 2 | 3 |
2 | 3 | 3 | 6 |
3 | 6 | 4 | 10 |
4 | 10 | 5 | 15 |

Thus, the final output of the reduce() function will be Optional(15). The use of Optional is crucial, as it accounts for the possibility of an empty stream, which would otherwise yield Optional.empty().

Section 1.2: Simple Reduction in Kotlin

Kotlin’s equivalent to the above reduce function is:

inline fun <S, T : S> Iterable<out T>.reduce(

operation: (acc: S, T) -> S

): S

A key distinction is that the return type S can be a supertype of type T from the input list. In contrast to Java, an empty list will lead to an UnsupportedOperationException. Here’s how you might implement this in Kotlin:

fun addNumbers(ints: List<Int>): Int {

return ints.reduce { acc, curr -> acc + curr }

}

As in Java, the result from the preceding iteration is utilized for the current iteration.

Chapter 2: Reduction with an Initial Value

Section 2.1: Using Reduction in Java

If you want to begin reduction with a predefined initial value in Java, you can employ:

T reduce(T identity, BinaryOperator<T> accumulator)

This variant accepts T identity as its first argument, serving dual purposes: as the initial value and as a default if the stream is empty. Consequently, this method returns T instead of Optional<T>, alleviating concerns about empty streams.

Here’s a sample function demonstrating this:

String removeSigns(final String input, final List<String> signs) {

return signs.stream()

.reduce(input, (acc, curr) -> acc.replace(curr, ""));

}

When calling this function with:

removeSigns("Str#€ange€ %&s#!ign/&s!",

List.of("!", "#", "€", "%", "&", "/"));

The following iterations are used:

iteration | acc | curr | return value |
1 | Str#€ange€ %&s#!ign/&s! | ! | Str#€ange€ %&s#ign/&s |
2 | Str#€ange€ %&s#ign/&s | # | Str€ange€ %&sign/&s |
3 | Str€ange€ %&sign/&s | € | Strange %&sign/&s |
4 | Strange %&sign/&s | % | Strange &sign/&s |
5 | Strange &sign/&s | & | Strange sign/s |
6 | Strange sign/s | / | Strange signs |

Section 2.2: Using Folding in Kotlin

In Kotlin, this variation of reduce, which includes an initial value, is known as fold():

inline fun <T, R> Iterable<T>.fold(

initial: R,

operation: (acc: R, T) -> R

): R

Here’s how the function would be structured in Kotlin:

fun removeSigns(input: String, signs: List<String>): String {

return signs.fold(input) { acc, curr -> acc.replace(curr, "") }

}

Chapter 3: MapReduce Concept

Kotlin allows for type flexibility in fold(), enabling different types for elements and return types. This flexibility is essential when manipulating elements before reducing them, a process known as MapReduce.

Consider this example involving a Salesperson class:

data class Salesperson(

val name: String,

val revenue: Double

)

private val salespersons = listOf(

Salesperson("Nils Nilsson", 1_000_000.0),

Salesperson("Lars Larsson", 2_000_000.0),

Salesperson("Bertil Bertilsson", 5_000_000.0)

)

To collect and sum their revenues using Kotlin's fold():

fun sumSalespersonRevenue(salespersons: List<Salesperson>): Double {

return salespersons.fold(0.0) { acc, salesperson ->

acc + salesperson.revenue

}

}

In Java, however, types must match. To achieve the same, you need to combine reduce() with map():

double sumSalespersonRevenue(List<Salesperson> salespersons) {

return salespersons.stream()

.map(Salesperson::getRevenue)

.reduce(0.0, Double::sum);

}

This method enhances code readability with method references.

The following video explores how Kotlin enhances Java code:

Chapter 4: Advanced Reduction Examples

Section 4.1: Calculating Pi in Java

For a more complex example, let's calculate π using the Leibniz formula:

double calcPi(final long iterations) {

final var result = DoubleStream

.iterate(3.0, (x) -> x + 2)

.limit(iterations)

.reduce(1.0,

(acc, curr) -> {

final var res = acc - 1 / curr;

return -res;

}

);

return Math.abs(result * 4);

}

This function creates a DoubleStream and limits the number of iterations, affecting the precision of the result.

Section 4.2: Calculating Pi in Kotlin

The equivalent function in Kotlin is:

fun calcPi(iterations: Int): Double {

val value = generateSequence(3.0, { it + 2 })

.take(iterations)

.fold(1.0) { acc, curr ->

-(acc - 1 / curr)

}

return abs(value * 4)

}

Here, we generate a sequence, limit it, and apply similar logic to the Java function.

Final Thoughts

While Java includes a third reduce function, it's less relevant to our discussion, as many reductions can be simplified using explicit combinations of map and reduce operations. Furthermore, there's no Kotlin equivalent for this function.

Another reduction method in Java is through the Stream.collect() method, which you can explore further in Java's tutorial resources.

I wrote this article partly to deepen my understanding of map and reduce concepts. Working daily with Java and Kotlin, it has been beneficial to compare implementations in both languages. I hope you find this guide insightful.

Happy coding with reduction!

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Stop Overthinking Your Purpose — It’s Hurting Your Happiness

Discover how to find purpose without the stress of overthinking it. Embrace small beginnings and cultivate gratitude for a fulfilling life.

Understanding the Challenges of Bias in Scientific Research

An exploration of cognitive biases in science and their impact on research integrity and outcomes.

Title: Navigating Your Path to Recovery: The FASTT Check-In Method

Discover the FASTT check-in method to support your recovery journey from pornography addiction and foster accountability.

Experience the Magic of the Perseid Meteor Shower This August

Get ready for the Perseid Meteor Shower, a chance to witness shooting stars with family and friends this August.

Exploring the Existence of Distant Stars: What We Know

This article delves into the fascinating concept of whether distant stars still exist, exploring how scientists study celestial bodies.

# The Emotional Turmoil Following Divorce: Understanding the Struggle

Explore the emotional aftermath of divorce through the experiences of women grappling with feelings of regret and loss.

Insights from System1's CFO Chris Willford at Upcoming Event

Chris Willford, CFO of System1, will engage in a fireside chat to discuss insights on the digital advertising landscape and the company's 2024 strategies.

Avoid These Common Writing Pitfalls: A Guide to Success

Discover the top 3 mistakes to avoid in your writing journey and how to succeed on Medium.