Jsp – Calculate total sum of all numbers in c:forEach loop

foreachjspjstlsum

I have a Java bean like this:

class Person {
  int age;
  String name;
}

I'd like to iterate over a collection of these beans in a JSP, showing each person in a HTML table row, and in the last row of the table I'd like to show the total of all the ages.

The code to generate the table rows will look something like this:

<c:forEach var="person" items="${personList}">
  <tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>

However, I'm struggling to find a way to calculate the age total that will be shown in the final row without resorting to scriptlet code, any suggestions?

Best Solution

Note: I tried combining answers to make a comprehensive list. I mentioned names where appropriate to give credit where it is due.

There are many ways to solve this problem, with pros/cons associated with each:

Pure JSP Solution

As ScArcher2 mentioned above, a very easy and simple solution to the problem is to implement it directly in the JSP as so:

<c:set var="ageTotal" value="${0}" />
<c:forEach var="person" items="${personList}">
  <c:set var="ageTotal" value="${ageTotal + person.age}" />
  <tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>
${ageTotal}

The problem with this solution is that the JSP becomes confusing to the point where you might as well have introduced scriplets. If you anticipate that everyone looking at the page will be able to follow the rudimentary logic present it is a fine choice.

Pure EL solution

If you're already on EL 3.0 (Java EE 7 / Servlet 3.1), use new support for streams and lambdas:

<c:forEach var="person" items="${personList}">
  <tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>
${personList.stream().map(person -> person.age).sum()}

JSP EL Functions

Another way to output the total without introducing scriplet code into your JSP is to use an EL function. EL functions allow you to call a public static method in a public class. For example, if you would like to iterate over your collection and sum the values you could define a public static method called sum(List people) in a public class, perhaps called PersonUtils. In your tld file you would place the following declaration:

<function>
  <name>sum</name>
  <function-class>com.example.PersonUtils</function-class>
  <function-signature>int sum(java.util.List people)</function-signature>
</function> 

Within your JSP you would write:

<%@ taglib prefix="f" uri="/your-tld-uri"%>
...
<c:out value="${f:sum(personList)}"/>

JSP EL Functions have a few benefits. They allow you to use existing Java methods without the need to code to a specific UI (Custom Tag Libraries). They are also compact and will not confuse a non-programming oriented person.

Custom Tag

Yet another option is to roll your own custom tag. This option will involve the most setup but will give you what I think you are esentially looking for, absolutly no scriptlets. A nice tutorial for using simple custom tags can be found at http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags5.html#74701

The steps involved include subclassing TagSupport:

public PersonSumTag extends TagSupport {

   private List personList;

   public List getPersonList(){
      return personList;
   }

   public void setPersonList(List personList){
      this.personList = personList;
   }

   public int doStartTag() throws JspException {
      try {
        int sum = 0;
        for(Iterator it = personList.iterator(); it.hasNext()){
          Person p = (Person)it.next();
          sum+=p.getAge();
        } 
        pageContext.getOut().print(""+sum);
      } catch (Exception ex) {
         throw new JspTagException("SimpleTag: " + 
            ex.getMessage());
      }
      return SKIP_BODY;
   }
   public int doEndTag() {
      return EVAL_PAGE;
   }
}

Define the tag in a tld file:

<tag>
   <name>personSum</name>
   <tag-class>example.PersonSumTag</tag-class>
   <body-content>empty</body-content>
   ...
   <attribute>
      <name>personList</name>
      <required>true</required>
      <rtexprvalue>true</rtexprvalue>
      <type>java.util.List</type>
   </attribute>
   ...
</tag>

Declare the taglib on the top of your JSP:

<%@ taglib uri="/you-taglib-uri" prefix="p" %>

and use the tag:

<c:forEach var="person" items="${personList}">
  <tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>
<p:personSum personList="${personList}"/>

Display Tag

As zmf mentioned earlier, you could also use the display tag, although you will need to include the appropriate libraries:

http://displaytag.sourceforge.net/11/tut_basic.html

Related Question