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

  • Your Codebase Is a Cluttered Garage

Trending

  • Introducing Graph Concepts in Java With Eclipse JNoSQL, Part 2: Understanding Neo4j
  • Advancing Your Software Engineering Career in 2025
  • Building a Real-Time Audio Transcription System With OpenAI’s Realtime API
  • Efficient API Communication With Spring WebClient

Removing Duplicate Code With Lambda Expressions

If you don't want to use frameworks to handle duplicated code or JPA transactions, you can do it using Java's own syntax—lambda expressions and anonymous classes.

By 
Enrique Molinari user avatar
Enrique Molinari
·
Feb. 09, 17 · Tutorial
Likes (25)
Comment
Save
Tweet
Share
24.7K Views

Join the DZone community and get the full member experience.

Join For Free

In this article, we'll go over a concrete example of removing duplicated code by using lambda expressions. 

For this demonstration, I will be showing a basic example requiring us to persist objects using JPA (Java Persistence API). 

Suppose we are asked to write some code to do a simple save, update, and retrieve of a specific Entity class, using JPA (more on this is at copypasteisforword). To implement that, I will write a class called ADataAccessObject (just to name it somehow). Below, you will find what I would have written in my first development iteration — the make it work step.

public class ADataAccessObject {

    private EntityManagerFactory emf;

    public ADataAccessObject(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public void save(AnEntity anEntity) {
        EntityManager em = this.emf.createEntityManager();
        EntityTransaction tx = null;
        try {
            tx = em.getTransaction();
            tx.begin();

            em.persist(anEntity);

            tx.commit();
        } catch (Exception e) {
            if (tx != null) {
                tx.rollback();
            }
            throw new RuntimeException(e);
        } finally {
            em.close();
        }
    }

    public void update(long id, String aNewPropertyValue) {
        EntityManager em = this.emf.createEntityManager();
        EntityTransaction tx = null;
        try {
            tx = em.getTransaction();
            tx.begin();

            AnEntity anEntity = em.find(AnEntity.class, id);
            anEntity.setAProperty(aNewPropertyValue);

            tx.commit();
        } catch (Exception e) {
            if (tx != null) {
                tx.rollback();
            }
            throw new RuntimeException(e);
        } finally {
            em.close();
        }
    }

    public AnEntity byId(long id) {
        EntityManager em = this.emf.createEntityManager();
        try {
            return em.find(AnEntity.class, id);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            em.close();
        }
    }
}


Now let's write the client code that uses the class above:

public class Main {
    public static void main(String arg[]) {
        EntityManagerFactory emf = null;
        try {
            emf = Persistence
                .createEntityManagerFactory("a-persistence-name");
            ADataAccessObject dao = new ADataAccessObject(emf);
            //store anEntity ...
            dao.store(new AnEntity("aValuForTheProperty"));
            //update anEntity ...
            dao.update(1 l, "anotherValueForTheProperty");
            //retrieving ...
            AnEntity e = dao.byId(1 l);
        } finally {
            emf.close();
        }
    }


What doesn't look nice from the class ADataAccessObject above? As you might have noticed, each method seems to be pretty similar. The try/catch/finally skeleton with the creation of the EntityManager, the Transaction#commit, Transaction#rollback and the EntityManager#close, is duplicated.

To clarify a bit more, below are the sentences unique per method:

//from ADataAccessObject#store
em.persist(anEntity);

//from ADataAccessObject#update
AnEntity anEntity = em.find(AnEntity.class, id);
anEntity.setAProperty(aNewPropertyValue);

//from ADataAccessObject#byId
return em.find(AnEntity.class, id);


The other lines of code are duplicated in the three methods.

How can we remove that duplicated code? There are some options. You can use Dynamic Proxies or AspectJ. Or incorporate a framework like Spring to handle JPA transactions for you. Do we have a simpler approach? I don’t want to incorporate any frameworks, and I would love for the language itself to provide the syntactical constructions to do it.

What if the programming language allows you to pass a block of code as a method parameter? That sounds great because I can create a private method in my ADataAccessObject class with the try/catch/finally structure and receive each unique block of sentences by parameter.

Before Java 8, this was possible using Anonymous Classes. Lets moving ahead with this approach then.

For implementing this approach we have to create an Interface to specify the signature of the block of code that we need to pass by parameter. Described next:

public interface ABlockOfCode {
    AnEntity execute(EntityManager em);
}


That Inteface above is the type of my block of code. Each block of code will respond to the execute method. It must receive the EntityManager by parameter and must return AnEntity.

Let's go through the second iteration of my code — the make it better step. I will refactor my ADataAccessObject Class a bit, adding some anonymous classes to eliminate duplicated code.

public class ADataAccessObject {

    private EntityManagerFactory emf;

    public ADataAccessObject(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public void store(AnEntity anEntity) {
        transactionExecute(new ABlockOfCode() {
            @Override
            public AnEntity execute(EntityManager em) {
                em.persist(anEntity);
                return null;
            }
        });
    }

    public void update(long id, String aNewPropertyValue) {
        transactionExecute(new ABlockOfCode() {
            @Override
            public AnEntity execute(EntityManager em) {
                AnEntity anEntity = em.find(AnEntity.class, id);
                anEntity.setAProperty(aNewPropertyValue);
                return null;
            }
        });
    }

    public AnEntity byId(long id) {
        return transactionExecute(new ABlockOfCode() {
            @Override
            public AnEntity execute(EntityManager em) {
                return em.find(AnEntity.class, id);
            }
        });
    }

    private AnEntity transactionExecute(ABlockOfCode aBlockOfCode) {
        EntityManager em = this.emf.createEntityManager();
        EntityTransaction tx = null;
        try {
            tx = em.getTransaction();
            tx.begin();

            AnEntity a = aBlockOfCode.execute(em);

            tx.commit();
            return a;
        } catch (Exception e) {
            if (tx != null) {
                tx.rollback();
            }
            throw new RuntimeException(e);
        } finally {
            em.close();
        }
    }
}


As you can see, I have created a private method called transactionExecute, which expects as parameter an instance of ABlockOfCode. In each public method, I’m creating these instances as anonymous classes, implementing the execute method of the ABlockOfCode with the sentences unique per method described before. Then, each method calls transactionExecute, passing these ABlockOfCode instances by parameter. Finally, note that inside the transactionExecute method, there is a call to the execute method of the ABlockOfCode instance, inside the try/catch/finally skeleton.

Not bad right? Let’s do it even better in my third development iteration. I’m going to replace the anonymous classes with lambdas. In Java 8, lambdas are a prettier way of writing anonymous classes (not exactly the case for functional programming languages, but that is a different talk). They incorporate a syntactic sugar plus a type inference system, which make the code cleaner and easier to read.

The code below starts moving the transactionExecute private method to its own class.

public class TransactionTemplate {
    public EntityManagerFactory emf;

    public TransactionTemplate(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public AnEntity execute(ABlockOfCode aBlockOfCode) {
        EntityManager em = this.emf.createEntityManager();
        EntityTransaction tx = null;
        try {
            tx = em.getTransaction();
            tx.begin();

            AnEntity returnValue = aBlockOfCode.execute(em);

            tx.commit();
            return returnValue;
        } catch (Exception e) {
            if (tx != null) {
                tx.rollback();
            }
            throw new RuntimeException(e);
        } finally {
            em.close();
        }
    }
}

public class ADataAccessObject {

    private TransactionTemplate transaction;

    public ADataAccessObject(TransactionTemplate transaction) {
        this.transaction = transaction;
    }

    public void store(AnEntity anEntity) {
        transaction.execute(
            (em) - > {
                em.persist(anEntity);
                return null;
            });
    }

    public void update(long id, String aNewPropertyValue) {
        transaction.execute(
            (em) - > {
                AnEntity anEntity = em.find(AnEntity.class, id);
                anEntity.setAProperty(aNewPropertyValue);
                return null;
            });
    }

    public AnEntity byId(long id) {
        return transaction.execute(
            (em) - > {
                return em.find(AnEntity.class, id);
            });
    }
}


A lambda expression (lines 40-42, 47-50 and 55-57), is composed of two parts separated by the lexical token “->”: (parameters) -> { block of code }. There is no need to specify the type of the parameter in the lambda expression, it will be inferred from an interface, in this case, the ABlockOfCode. If you look at this interface, you will note that each lambda expression receives an instance of the EntityManager as a parameter, (em), and must return an instance of AnEntity. Nice, duplicated code removed and less verbose code.

As a final development iteration, I will make this more generic. My ABlockOfCode interface and TransactionTemplate class should support any object type, not only AnEntity. So next, I will change the AnEntity type for a generic type T.

Starting with the ABlockOfCode interface:

public interface ABlockOfCode<T> {
    T execute(EntityManager em);
}


I have just replaced AnEntity with the generic type T, and I have declared that type T as a generic type, using the <T> syntax (on line 1).

Next, I will make the TransactionTemplate#execute method generic:

public < T > T execute(ABlockOfCode < T > aBlockOfCode) {
    EntityManager em = this.emf.createEntityManager();
    EntityTransaction tx = null;
    try {
        tx = em.getTransaction();
        tx.begin();

        T returnValue = aBlockOfCode.execute(em);

        tx.commit();
        return returnValue;
    } catch (Exception e) {
        if (tx != null) {
            tx.rollback();
        }
        throw new RuntimeException(e);
    } finally {
        em.close();
    }
}


On line 1, I’m declaring the generic type <T>, changing the signature of the method returning T and expecting ABlockOfCode<T> as a parameter. Note also that the return type of the aBlockOfCode.execute(em) sentence has changed from AnEntity to T, on line 8.

With this last change, we have made the TransactionTemplate#execute method generic to be used by any instance of ABlockOfCode that requires a JPA transaction context. The ADataAccessObject class does not need to change because, as I explained before, the lambdas infer their type from the ABlockOfCode interface.

We just went through some development iterations in order to remove duplicated code. The nature of the duplicated code shown here is not able to be removed using simple refactoring techniques like the extract method or extract class. It requires more powerful language features to allow passing sentences, or blocks of code, by parameter. That was achieved using anonymous classes first, and then with lambda expressions since Java 8. 

Duplicate code

Published at DZone with permission of Enrique Molinari. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Your Codebase Is a Cluttered Garage

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!