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

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

SBOMs are essential to circumventing software supply chain attacks, and they provide visibility into various software components.

Related

  • Exploring Exciting New Features in Java 17 With Examples
  • Projections/DTOs in Spring Data R2DBC
  • Testcontainers With Kotlin and Spring Data R2DBC
  • Build a Java Microservice With AuraDB Free

Trending

  • Continuous Quality Engineering: The Convergence of CI/CD, Chaos Testing, and AI-Powered Test Orchestration
  • Build Real-Time Analytics Applications With AWS Kinesis and Amazon Redshift
  • Microservice Madness: Debunking Myths and Exposing Pitfalls
  • Building an AI Nutrition Coach With OpenAI, Gradio, and gTTS
  1. DZone
  2. Data Engineering
  3. Data
  4. Creating Maps With Named Lambdas

Creating Maps With Named Lambdas

Learn how you can create a Java Map like this: map = mapOf(one -> 1, two -> 2) using a trick to get the lambda parameter name.

By 
Per-Åke Minborg user avatar
Per-Åke Minborg
·
Dec. 07, 16 · Tutorial
Likes (49)
Comment
Save
Tweet
Share
23.2K Views

Join the DZone community and get the full member experience.

Join For Free

The Magical Map

Wouldn't it be great if we could create Java maps like this?

Map<String, Integer> map = mapOf(
      one -> 1,
      two -> 2
);

Map<String, String> map2 = mapOf(
      one -> "eins",
      two -> "zwei"
);


Well, we can! [UPDATE: Check out the last clause in this article before you use it in your own code] Read this post and learn more about lambdas and how we can get the name of their parameters.

The Solution

By introducing the following interface, we get the functionality above.

public interface KeyValueStringFunction<T> extends Function<String, T>, Serializable {

    default String key() {
        return functionalMethod().getParameters()[0].getName();
    }

    default T value() {
        return apply(key());
    }

    default Method functionalMethod() {
        final SerializedLambda serialzedLabmda = serializedLambda();
        final Class<?> implementationClass = implementationClass(serialzedLabmda);
        return Stream.of(implementationClass.getDeclaredMethods())
            .filter(m -> Objects.equals(m.getName(), serialzedLabmda.getImplMethodName()))
            .findFirst()
            .orElseThrow(RuntimeException::new);
    }

    default Class<?> implementationClass(SerializedLambda serializedLambda) {
        try {
            final String className = serializedLambda.getImplClass().replaceAll("/", ".");
            return Class.forName(className);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    default SerializedLambda serializedLambda() {
        try {
            final Method replaceMethod = getClass().getDeclaredMethod("writeReplace");
            replaceMethod.setAccessible(true);
            return (SerializedLambda) replaceMethod.invoke(this);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @SafeVarargs
    static <V> Map<String, V> mapOf(KeyValueStringFunction<V>... mappings) {
        return Stream.of(mappings)
          .collect(
              toMap(
                  KeyValueStringFunction::key,
                  KeyValueStringFunction::value
              )
          );
    }

}


Limitations

We can only create maps with keys that are of type String (or anything super String like CharSequence, Serializable, or Comparable<String>) because, obviously, lambda names are strings.

We must use a Java version that is higher than Java 8u80 because it was at that time that lambda names could be retrieved at runtime.

The most annoying limitation is that we have to compile (i.e. "javac") our code with the "-parameter" flag, or else the parameter names will not be included in the run time package (e.g. JAR or WAR). We can do this automatically by modifying our POM file like this:

          <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerArgs>
                        <arg>-Xlint:all</arg>
                        <!-- Add this line to your POM -->
                        <arg>-parameters</arg>
                    </compilerArgs>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>


If you forget to add the "-parameter" flag, the Java runtime will always report a default name of "arg0" as the name of the parameter. This leads to that the maps will (at most) contain one key "arg0", which is not what we want.

Opportunities

The values, can be of any type. In particular they can be other maps, enabling us to construct more advanced map hierarchies. We could, for example, create a map with different countries with values that are also maps containing the largest towns and how many inhabitants each city has like this:

Map<String, Map<String, Integer>> map3 = mapOf(

            usa -> mapOf(
                new_york    -> 8_550_405,
                los_angeles -> 3_971_883,
                chicago     -> 2_720_546
            ),
            canada -> mapOf(
                toronto  -> 2_615_060,
                montreal -> 1_649_519,
                calgary  -> 1_096_833
            )

        );


Update: Important Notes

A number of people have pointed out that SerializedLambda is "thin ice" that we should not rely on in production code. Tagir Valeev (@tagir_valeev) made a performance test of the scheme in this post and compared it to the old fashioned way of just creating a Map and using a regular put() to enter data. The findings were that the old way is orders of magnitudes faster.  You can find the entire benchmark here. Thanks Tagir for making this test available.

You should view this way of entering data in a Map as academic an as an inspiration of what can be done in Java. Do not use it in production code.

Keep on mapping!

Java (programming language) Strings Data (computing) Testing Production (computer science) Data Types POST (HTTP) Scheme (programming language)

Published at DZone with permission of Per-Åke Minborg, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Exploring Exciting New Features in Java 17 With Examples
  • Projections/DTOs in Spring Data R2DBC
  • Testcontainers With Kotlin and Spring Data R2DBC
  • Build a Java Microservice With AuraDB Free

Partner Resources

×

Comments

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

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

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 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: