DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Java Stream API: 3 Things Every Developer Should Know About
  • Optimizing Java Applications: Parallel Processing and Result Aggregation Techniques
  • Functional Approach To String Manipulation in Java
  • Techniques You Should Know as a Kafka Streams Developer

Trending

  • Designing Effective Meetings in Tech: From Time Wasters to Strategic Tools
  • Your API Authentication Isn’t Broken; It’s Quietly Failing in These 6 Ways
  • Fact-Checking LLM Outputs Programmatically: Building a Verification Layer That Catches Hallucinations
  • Edge Computing in Utility IoT: Two Architecture Patterns That Actually Work
  1. DZone
  2. Data Engineering
  3. Databases
  4. Extending the Stream API to Maps

Extending the Stream API to Maps

Learn how Speedment Open Source streams efficiently over standard Java maps, expanding the Stream interface into something called a MapStream!

By 
Emil Forslund user avatar
Emil Forslund
·
Jan. 14, 16 · Tutorial
Likes (6)
Comment
Save
Tweet
Share
11.4K Views

Join the DZone community and get the full member experience.

Join For Free

One of the bigest features in Java 8 is the ability to stream over collections of objects. By adding the .stream()-method into the Collection interface, every collection in the java language is suddenly expanded with this new ability. Other data structures like the Map-interface, do not implement the method as they are not, strictly speaking, collections.

In this article I will show you how Speedment Open Source streams efficiently over standard Java maps, expanding the Stream interface into something called a MapStream! This addition will make it easier to keep your streams concrete and readable even in complex scenarios. Hopefully this will allow you to keep streaming without prematurely collecting the result.

The MapStream will take two type parameters, a key and a value. It will also extends the standard Stream interface by specifying Map.Entry<K, V> as type parameter. This will allow us to construct a MapStream directly from any Java map.

public interface MapStream<K, V> extends Stream<Map.Entry<K, V>> {
    ...
}

The concept of polymorphism tells us that a child component may change the return type of an overidden method as long as the new return type is a more concrete implementation of the old return type. We will use this when defining the MapStream interface so that for each chaining operation, a MapStream is returned instead of a Stream.

public interface MapStream<K, V> extends Stream<Map.Entry<K, V>> {

    @Override 
    MapStream<K, V> filter(Predicate<? super Map.Entry<K, V>> predicate);

    @Override 
    MapStream<K, V> distinct();

    @Override
    MapStream<K, V> sorted(Comparator<? super Map.Entry<K, V>> comparator);

    ...
}

Some operations will still need to return an ordinary Stream. If the operation change the type of the streamed element, we can’t ensure that the new type will be a Map.Entry. We can, however, add additional methods for mapping between types with Key-Value pairs.


    @Override
    <R> Stream<R> map(Function<? super Map.Entry<K, V>, ? extends R> mapper);

    <R> Stream<R> map(BiFunction<? super K, ? super V, ? extends R> mapper);

In addition to the Function that let the user map from an Entry to something else, he or she can also map from a Key-Value-pair to something else. This is convenient, sure, but we can also add more specific mapping operations now that we are working with pairs of values.


    <R> MapStream<R, V> mapKey(BiFunction<? super K, ? super V, ? extends R> mapper);

    <R> MapStream<K, R> mapValue(BiFunction<? super K, ? super V, ? extends R> mapper);

The difference doesn’t look like much, but the difference is apparent when using the API:


// With MapsStream
final Map<String, List<Long>> map = ...;
MapStream.of(map)
    .mapKey((k, v) -> k + " (" + v.size() + ")")
    .flatMapValue((k, v) -> v.stream())
    .map((k, v) -> k + " >> " + v)
    .collect(System.out::println);

// Without MapStream
final Map<String, List<Long>> map = ...;
map.entrySet().stream()
    .map(e -> new AbstractMap.SimpleEntry<>(
         e.getKey() + " (" + e.getValue().size() + ")"),
         e.getValue()
    ))
    .flatMap(e -> e.getValue().stream()
        .map(v -> new AbstractMap.SimpleEntry<>(e.getKey(), v))
    )
    .map(e -> e.getKey() + " >> " + e.getValue())
    .collect(System.out::println);

The full implementation of MapStream can be found here. If you are interested in more cool stuff, have a look at the Speedment Github page. Have fun streaming!

API Stream (computing)

Published at DZone with permission of Emil Forslund. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Java Stream API: 3 Things Every Developer Should Know About
  • Optimizing Java Applications: Parallel Processing and Result Aggregation Techniques
  • Functional Approach To String Manipulation in Java
  • Techniques You Should Know as a Kafka Streams Developer

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook