Course topics

By WebNest Studio Engineering Team

Advanced Java Tutorial

JSP Scripting Elements

JSP scripting elements are the tags that let you embed Java code directly inside a page. There are three kinds — scriptlets, expressions, and declarations — and each is translated into a different part of the generated servlet, which is why they behave differently even though all three "contain Java code."

Scripting elements were the original way to add logic to a JSP page, and you will still encounter them in older codebases and in learning materials. Modern JSP development, however, deliberately avoids heavy use of them in favor of the Expression Language (EL) and the JSP Standard Tag Library (JSTL), for reasons explained below.

Scriptlets: <% ... %>

A scriptlet contains arbitrary Java statements and is copied directly into the generated servlet's _jspService() method, in the exact position it appears on the page. This means you can open a loop or an if-block in one scriptlet, write plain HTML in between (which becomes an out.println() inside that block), and close the loop or block in a later scriptlet — the HTML in between only renders when the surrounding Java logic says it should.

Expressions: <%= ... %>

An expression evaluates a single Java expression and inserts its String representation directly into the output, equivalent to wrapping it in out.print(...). Because it is inserted as an expression, it must not end with a semicolon, and it must genuinely evaluate to a value (not a statement).

Declarations: <%! ... %>

A declaration defines members — fields or methods — at the class level of the generated servlet, outside of _jspService(). This means variables declared here behave like servlet instance variables: they persist across requests and are shared by all users, exactly like a normal servlet's instance fields, which makes them just as dangerous for storing per-request state.

Why Modern JSP Avoids Heavy Scriptlets

Scriptlets mix Java and HTML in a way that is hard to read, hard to unit test, and impossible for non-Java developers (like front-end designers) to safely edit. The Expression Language (${...}) and JSTL tags (like <c:forEach> and <c:if>) were introduced specifically to replace common scriptlet patterns with cleaner, tag-based syntax that keeps logic in servlets/JavaBeans and keeps JSP focused on presentation — a separation of concerns that scriptlet-heavy pages break.

Example

All three scripting elements together, and the modern EL/JSTL replacement

Java
<%!
    // Declaration: class-level field, shared across ALL requests (be careful!)
    private int pageHitCounter = 0;
%>

<%
    // Scriptlet: ordinary Java, runs per request
    pageHitCounter++;
    String[] fruits = {"Apple", "Banana", "Cherry"};
%>

<html><body>
  <p>Page hits since server start: <%= pageHitCounter %></p>  <%-- Expression --%>

  <ul>
  <% for (String fruit : fruits) { %>
      <li><%= fruit %></li>
  <% } %>
  </ul>
</body></html>

<%-- Modern equivalent using EL + JSTL, no scriptlets: --%>
<%-- <ul>
       <c:forEach var="fruit" items="${fruits}">
         <li>${fruit}</li>
       </c:forEach>
     </ul> --%>
Output
Browser output:
Page hits since server start: 1  (increments on every reload, shared by all visitors)
- Apple
- Banana
- Cherry

Common Mistakes

  • Putting a semicolon at the end of an expression <%= x; %> — expressions must be a single value-producing expression, not a statement.
  • Declaring per-request state (like a counter meant to be per-user) inside a declaration block <%! %>, not realizing it becomes shared servlet-level state.
  • Splitting a Java control block (for/if) across multiple scriptlets and forgetting to close every brace, which produces a confusing generated-servlet compile error.
  • Writing large amounts of business logic directly in scriptlets instead of a servlet or JavaBean, making the page hard to test and maintain.

Exercise

A teammate is about to make this mistake: Putting a semicolon at the end of an expression <%= x; %> — expressions must be a single value-producing expression, not a statement. Use Scriptlets: <% ... %> to review the decision. Write a corrected implementation or design sketch that follows Scriptlets <% %> insert Java statements into _jspService(); expressions <%= %> insert a value via out.print(); declarations <%! %> add class-level members., then name one edge case you would check.

Show hints
  • Start with Scriptlets: <% ... %> and compare your approach with All three scripting elements together, and the modern EL/JSTL replacement. Identify the decision or behavior the lesson recommends.
  • Walk through your scenario step by step. Confirm that it follows Scriptlets <% %> insert Java statements into _jspService(); expressions <%= %> insert a value via out.print(); declarations <%! %> add class-level members. and that it would catch the failure described by Putting a semicolon at the end of an expression <%= x; %> — expressions must be a single value-producing expression, not a statement..

Quick quiz

1. Which choice best describes the recommended approach in JSP Scripting Elements?

  • A. Putting a semicolon at the end of an expression <%= x; %> — expressions must be a single value-producing expression, not a statement.
  • B. Declaring per-request state (like a counter meant to be per-user) inside a declaration block <%! %>, not realizing it becomes shared servlet-level state.
  • C. Scriptlets <% %> insert Java statements into _jspService(); expressions <%= %> insert a value via out.print(); declarations <%! %> add class-level members.
Show answer

C. This is the recommended approach: Scriptlets <% %> insert Java statements into _jspService(); expressions <%= %> insert a value via out.print(); declarations <%! %> add class-level members. Avoid: Putting a semicolon at the end of an expression <%= x; %> — expressions must be a single value-producing expression, not a statement.

Interview questions

Why does this principle matter in JSP Scripting Elements: Scriptlets <% %> insert Java statements into _jspService(); expressions <%= %> insert a value via out.print(); declarations <%! %> add class-level members.

Show answer

Scriptlets <% %> insert Java statements into _jspService(); expressions <%= %> insert a value via out.print(); declarations <%! %> add class-level members. Apply this in Scriptlets: <% ... %>; the example All three scripting elements together, and the modern EL/JSTL replacement shows one way to do it. Avoid Putting a semicolon at the end of an expression <%= x; %> — expressions must be a single value-producing expression, not a statement. and explain how your implementation or design prevents that failure.

Key Points to Remember

  • Scriptlets <% %> insert Java statements into _jspService(); expressions <%= %> insert a value via out.print(); declarations <%! %> add class-level members.
  • Declaration-block variables behave like servlet instance variables — shared across all requests and users.
  • Modern practice replaces scriptlet-heavy logic with Expression Language (${...}) and JSTL tags for readability and separation of concerns.
  • Expressions must not end with a semicolon; scriptlets can span multiple tags as long as braces balance.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering