Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to pass a method name as a parameter in Java

Is there a way to parameterize a method name?

Example:

JournalLine {

    BigDecimal ccyAmount;
    BigDecimal lcyAmount;
    BigDecimal rptAmount;
   
    // Getters and Setters
}

Original (working)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

// Calculate totals
BigDecimal totalCcyAmount = journalLines.stream()
                                        .map(journalLine -> journalLine.getCcyAmount())
                                        .reduce((a, b) -> a.add(b))
                                        .orElse(BigDecimal.ZERO);

BigDecimal totalLclAmount = journalLines.stream()
                                       .map(journalLine -> journalLine.getLclAmount())
                                       .reduce((a, b) -> a.add(b))
                                       .orElse(BigDecimal.ZERO);

BigDecimal totalRptAmount = journalLines.stream()
                                        .map(journalLine -> journalLine.getRptAmount())
                                        .reduce((a, b) -> a.add(b))
                                        .orElse(BigDecimal.ZERO);
                                    
                                    

This duplication is used in different locations of the application. Not always together.

Is there a way to do something like:

//Calculate totals and pass the method name
BigDecimal totalCcyAmount = getTotal(journalLines, "getCcyAmount");
BigDecimal totallclAmount = getTotal(journalLines, "getCcyAmount");
BigDecimal totalRptAmount = getTotal(journalLines, "getCcyAmount");
                                        
public BigDecimal getTotal( List<JournalLine> journalLines, String METHOD_NAME) {
    return journalLines.stream()
                         .map(journalLine -> journalLine.METHOD_NAME)
                         .reduce((a, b) -> a.add(b))
                         .orElse(BigDecimal.ZERO);
}

I want to pass METHOD_NAME (getCcyAmount() or getLcyAmount() or getRptAmount ())
or use a different approach to avoid duplication of code.

>Solution :

Without using reflection, your best choice is probably passing a FunctionalInterface to the method:

Method call:

getTotal(journalLines, JournalLine::getCcyAmount);

and the method looks like this:

public BigDecimal getTotal(List<JournalLine> journalLines,
        Function<JournalLine, BigDecimal> function) {
    return journalLines.stream().map(function).reduce((a, b) -> a.add(b))
            .orElse(BigDecimal.ZERO);
}

If you are really fixed on using a String as method argument, you wont get around using reflection. And that is where it becomes ugly, codewise:

private static BigDecimal getTotal(List<JournalLine> journalLines, String methodName) {
    Method method;
    try {
        method = JournalLine.class.getDeclaredMethod(methodName);
    } catch (NoSuchMethodException | SecurityException e2) {
        e2.printStackTrace();
        throw new RuntimeException("Unhandled", e2);
    }
    return journalLines.stream().map(e -> {
        try {
            return (BigDecimal) method.invoke(e);
        } catch (IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e1) {
            e1.printStackTrace();
            throw new RuntimeException("Unhandled", e1);
        }
    }).reduce((a, b) -> a.add(b)).orElse(BigDecimal.ZERO);
}

This would then work by calling

getTotal(list, "getCcyAmount");

However, you are way more prone to errors, by e.g. having a typo in your methodname string. The compiler can’t even tell you before running into an error, as it is just a String, until the reflection starts.


Overall I suggest using FunctionalInterfaces over reflection. Not only is the code less cluttered, but also you have the support of the compiler while coding.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading