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
Please enter at least three characters to search
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

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

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

Related

  • Deploying a Kotlin App to Heroku
  • Why You Should Migrate Microservices From Java to Kotlin: Experience and Insights
  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • How To Install CMAK, Apache Kafka, Java 18, and Java 19 [Video Tutorials]

Trending

  • Cloud Security and Privacy: Best Practices to Mitigate the Risks
  • Building Reliable LLM-Powered Microservices With Kubernetes on AWS
  • Immutable Secrets Management: A Zero-Trust Approach to Sensitive Data in Containers
  • How to Format Articles for DZone
  1. DZone
  2. Coding
  3. Languages
  4. Java vs. Kotlin: Lambdas and Functions

Java vs. Kotlin: Lambdas and Functions

Want to learn more about the differences between threads and coroutines in Java and Kotlin? Click this post to learn more about the changes Kotlin brings to the JVM.

By 
Diego Ojeda user avatar
Diego Ojeda
·
Updated Aug. 07, 18 · Analysis
Likes (3)
Comment
Save
Tweet
Share
14.0K Views

Join the DZone community and get the full member experience.

Join For Free

At Apiumhub, we work with a controller-less architecture called Pure MVP, which is based on the composition of functions and investment of dependencies. You can find more information about it in these articles: MVPP in iOS, MVPP on Android.

In today’s post, we will talk about Java and Kotlin, comparing lambdas and functions before the arrival of Kotlin and how we have improved the readability of our code thanks to Kotlin.

Java vs. Kotlin

Lambdas and Functions as Parameters

First, we need to link the events of the view with those of the service, instead of exposing the observable directly. We do this so that the other party can do the subscription. Next, we expose methods that receive functions as parameters; these functions will be executed when an event occurs either in the view or in the service, such as:

//KOTLIN

interface View {
  fun requestData(func: (isPaginating: Boolean) -> Unit)
  fun onDataLoaded(newData: Data)
}

interface Service {
  fun getData(isPaginating: Boolean)
  fun onDataLoaded(func: (data: Data) -> Unit)
}

class Presenter(view: View, service: Service) {
  init {
    view.requestData {
      service.getData(it)
    }
    service.onDataLoaded {
      view.onDataLoaded(it)
    }
  }
}


A similar implementation in Java would look like this:

//JAVA

public interface View {
    void requestData(Consumer func);
    void onDataLoaded(Data newData);
}

public interface Service {
    void getData(boolean isPaginating);
    void onDataLoaded(Consumer func);
}

public class Presenter {
    Presenter(final View view, final Service service) {
        view.requestData(service::getData);
        service.onDataLoaded(view::onDataLoaded);
    }
}


The main difference between these implementations — Java vs. Kotlin — is the fact that in Java we need to use the Consumerclass to pass a function as a parameter. In this case, a function that receives an input parameter of the Boolean type does not return anything. If we wanted this function that we passed as a parameter to return something, we would have to change Consumer to Function, and if we didn’t want to have an input parameter, we would have to use Supplier instead. But, this does not end here. Instead of having one parameter, we would like to have two. Therefore, we need to use the BiFunction  or BiConsumer. If we would like to have three instead of two, Java does not provide us with a solution as we might expect (TriFunction or TriConsumer). Another option is to build it by ourselves or use the Function <T, Function <U, R >> or Function <Function <T, R>, U>. Any of these solutions are definitely less readable and more complicated to define and implement than that provided by Kotlin, where this option is integrated into the language itself.

The .apply Operator

When we have to instantiate a Fragment , Android makes us do it through a static method that we build with a Bundle to write the arguments that we want to pass to the Fragment. This is because the Bundle is stored by the operating system in order to rebuild this Fragment, in case it is destroyed.

In Java, we would need to do something like this:

static MyFragment newInstance(String arg1, String arg2) {
  MyFragment fragment = new MyFragment();
  Bundle arguments = new Bundle();
  arguments.putString(ARG_1_KEY, arg1);
  arguments.putString(ARG_2_KEY, arg2);
  fragment.setArguments(arguments);
  return fragment;
}


However, in Kotlin, we can do this using the .apply  operator. It should look something like this:

companion object {
  fun newInstance(arg1: String, arg2: String): MyFragment {
    return MyFragment().apply {
      arguments = Bundle().apply {
        putString(ARG_1_KEY, arg1)
        putString(ARG_2_KEY, arg2)
      }
    }
  }
}


While there is no difference in the number of lines between the two snippets, in Kotlin, it is not necessary to keep references to the Fragmentor the Bundle. We can also narrow the scope of each part of the code, since we know that within each . apply we are writing code that will refer to the object that we have made the .apply.

  •  Internal modifier: Another point in favor of Kotlin, with respect to Java, is the internal visibility modifier. This gives us visibility to a class, method, interface, etc. that is bounded to the located module. This is especially interesting if we don’t want to put it under a test functionality or expose it outside of our module, making it public.
  • Coroutines: Another new benefit that Kotlin gives us — although it is still experimental in version 1.1 — are coroutines. A coroutine is nothing more than a block of code that executes asynchronously to the thread from which it was invoked. We can think that the threads as already there, but there are several differences:
    • With a thread, the operating system is in charge of managing the execution, suspension, continuation, and change of context. These operations are heavy, and if we try to launch a high number of threads, for example, a million, our processor will collapse and spend more time changing from one thread to another, rather than executing the code we want it to execute. This is because a thread that we instantiate in Java (or Kotlin) corresponds to a thread of the operating system (either physical or virtual). Therefore, it is the scheduler of the operating system that is in charge of prioritizing which thread should be executed in every moment.
    • However, a coroutine does not have a correspondence with an operating system thread, but, instead, it is the language itself (in this case, the JVM) that is responsible for executing each of the coroutines and switching between them when necessary. In an example of the documentation of Kotlin, we can see this situation and the comparison between one million threads and one million coroutines:
val c = AtomicInteger()

for (i in 1..1_000_000)
    thread(start = true) {
        c.addAndGet(i)
    }

println(c.get())


val c = AtomicInteger()

for (i in 1..1_000_000)
    launch {
        c.addAndGet(i)
    }

println(c.get())


Conclusion

The results of this experiment suggest that it is faster to use coroutines rather than threads. Although this is not a comparison between Java and Kotlin, we can compare the functionality that is widely used in Java (threads) with a functionality implemented in Kotlin (coroutines).

These are just some of the changes that Kotlin brings us, with respect to Java, that makes our lives easier when developing applications for the JVM. 

Kotlin (programming language) Java (programming language) operating system

Published at DZone with permission of Diego Ojeda. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Deploying a Kotlin App to Heroku
  • Why You Should Migrate Microservices From Java to Kotlin: Experience and Insights
  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • How To Install CMAK, Apache Kafka, Java 18, and Java 19 [Video Tutorials]

Partner Resources

×

Comments
Oops! Something Went Wrong

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
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!