EL式(Expression Language)徹底解説 – JSP開発の新たな表現力
2025-08-04EL式とは何か
Expression Language(EL式)は、JSPページ内でデータにアクセスし操作するための簡潔な言語です。JSP 2.0から標準導入され、スクリプトレットに代わるより洗練されたデータアクセス方法を提供します。
EL式は、${expression}という簡潔な構文で記述でき、文字列と基本データ型の自動型変換を行います。また、スコープ内の暗黙オブジェクトへ容易にアクセスでき、EL 2.2以降ではメソッド呼び出しも可能です。さらに、null値に対しても安全に動作し、NullPointerExceptionを発生させないという特徴があります。
従来のスクリプトレットや式と比較して、より安全で読みやすいコードを記述できます。
EL式の基本構文
基本的なEL式の形式
${expression}は、JSPで使用されるEL式(Expression Language)の基本構文で、変数やオブジェクトの値を簡潔に出力するために使われます。スクリプトレットを使わずにデータを表示でき、可読性の高いテンプレート記述を実現します。
${expression}
スクリプトレット式との比較
スクリプトレット式
<%= request.getAttribute("userName") %>は、JSPのスクリプトレット式で、リクエストスコープからuserNameという属性値を取得して出力します。EL式${userName}と同様の結果を得られますが、コードが長くなり可読性が低下する点が異なります。
<%= request.getAttribute("userName") %>
EL式
${userName}は、JSPのEL式でリクエストやセッションなどのスコープ内にあるuserName属性の値を簡潔に出力します。スクリプトレットを使わずに記述できるため、コードの可読性と保守性が向上します。
${userName}
スクリプトレット式(型変換が必要)
<%= ((Integer)request.getAttribute("age")).intValue() + 10 %>は、JSPのスクリプトレット式で、リクエストスコープから取得したage属性(整数型)に10を加え、その結果を出力します。型変換を明示的に行う必要があり、EL式に比べて記述が複雑です。
<%= ((Integer)request.getAttribute("age")).intValue() + 10 %>
EL式(自動型変換)
${age + 10}は、JSPのEL式でスコープ内のage属性に10を加算し、その結果を出力します。EL式では自動的に型変換が行われるため、スクリプトレットよりも簡潔で可読性の高い記述が可能です。
${age + 10}
EL式の変数参照
スコープを指定したアクセス
スクリプトレットでのアクセス
このコードは、JSPで異なるスコープからproduct属性を取得して出力する例です。pageContext.findAttribute("product")はページ・リクエスト・セッション・アプリケーションの順に検索し、最初に見つかった値を返します。その他の行はそれぞれ特定のスコープ(request、session、application)から直接productを取得します。
<%= pageContext.findAttribute("product") %>
<%= request.getAttribute("product") %>
<%= session.getAttribute("product") %>
<%= application.getAttribute("product") %>
EL式でのアクセス(自動的にすべてのスコープを検索)
${product}は、JSPのEL式でスコープ内にあるproduct属性の値を自動的に検索して出力します。検索順序は、page → request → session → applicationの順で、最初に見つかった値が表示されます。簡潔で可読性の高い記述が可能です。
${product}
明示的なスコープ指定
このコードは、EL式を使って各スコープに格納されたproduct属性を明示的に参照し、出力する例です。pageScope、requestScope、sessionScope、applicationScopeを指定することで、同じ名前の属性が複数スコープに存在する場合でも、どのスコープの値を取得するかを明確に指定できます。
${pageScope.product} <%-- ページスコープ --%>
${requestScope.product} <%-- リクエストスコープ --%>
${sessionScope.product} <%-- セッションスコープ --%>
${applicationScope.product} <%-- アプリケーションスコープ --%>
JavaBeanプロパティへのアクセス
スクリプトレットでのアクセス
<%= ((User)request.getAttribute("user")).getName() %>は、JSPのスクリプトレット式で、リクエストスコープから取得したuserオブジェクトをUser型にキャストし、そのgetName()メソッドの戻り値(ユーザー名など)を出力します。EL式${user.name}で同様の結果をより簡潔に表現できます。
<%= ((User)request.getAttribute("user")).getName() %>
EL式でのアクセス
${user.name}は、JSPのEL式でスコープ内のuserオブジェクトのnameプロパティを取得して出力します。内部的にはgetName()メソッドが呼び出され、スクリプトレットよりも簡潔で可読性の高い記述が可能です。
${user.name}
ネストしたプロパティにもアクセス可能
${user.address.prefecture}は、JSPのEL式でuserオブジェクトの中にあるaddressオブジェクトのprefectureプロパティを参照して出力します。内部的にはgetUser().getAddress().getPrefecture()と同等の処理を行い、ネストしたオブジェクトの値を簡潔に取得できます。
${user.address.prefecture}
EL式の演算子
EL式とスクリプトレットの両方で使用できる主な算術演算子は、加算(+)、減算(-)、乗算(*)、除算(/ または div)、剰余(% または mod)です。
スクリプトレットではJavaの演算子として記述しますが、EL式では自動型変換が行われるため、より簡潔に計算を表現できます。また、EL式ではdivやmodといったキーワードでも演算を行える点が特徴です。
算術演算子
スクリプトレット
<%= (Integer)request.getAttribute("price") * 1.08 %>は、JSPのスクリプトレット式で、リクエストスコープから取得したprice属性(整数型)に1.08を掛けて税込価格を計算し、その結果を出力します。明示的な型変換が必要で、EL式に比べて記述が冗長です。
<%= (Integer)request.getAttribute("price") * 1.08 %>
EL式
${price * 1.08}は、JSPのEL式でスコープ内のprice属性に1.08を掛け、税込価格を計算して出力します。EL式では自動的に型変換が行われるため、スクリプトレットよりも簡潔で読みやすい記述が可能です。
${price * 1.08}
比較演算子
EL式とスクリプトレットの両方で使用できる主な比較演算子には、等しい(== または eq)、等しくない(!= または ne)、より小さい(< または lt)、より大きい(> または gt)、以下(<= または le)、以上(>= または ge)があります。
スクリプトレットではJavaの比較演算子を用いて条件を記述しますが、EL式では英単語(eq、neなど)でも記述できるため、可読性が高くHTMLテンプレート内で直感的に使用できます。
スクリプトレット
<%= ((Integer)request.getAttribute("age")).intValue() >= 20 %>は、JSPのスクリプトレット式でリクエストスコープから取得したage属性を整数にキャストし、その値が20以上かどうかを比較して真偽値(trueまたはfalse)を出力します。型変換を明示的に行う必要があり、EL式に比べて記述が冗長です。
<%= ((Integer)request.getAttribute("age")).intValue() >= 20 %>
EL式
${age >= 20}は、JSPのEL式でスコープ内のage属性が20以上かどうかを比較し、その結果を真偽値(trueまたはfalse)として出力します。EL式では自動的に型変換が行われるため、スクリプトレットよりも簡潔で可読性の高い記述が可能です。
${age >= 20}
論理演算子
EL式とスクリプトレットの両方で使用できる主な論理演算子には、論理積(&& または and)、論理和(|| または or)、否定(! または not)があります。
スクリプトレットではJavaの演算子を使用しますが、EL式ではandやor、notといった英単語でも記述でき、より可読性の高い条件式を簡潔に表現できます。
スクリプトレット
<%= ((Boolean)request.getAttribute("isMember")).booleanValue() && ((Integer)request.getAttribute("age")).intValue() >= 20 %>は、JSPのスクリプトレット式で、リクエストスコープから取得したisMemberがtrueで、かつageが20以上であるかを論理演算で判定し、その結果(true/false)を出力します。複数の型変換が必要なため、EL式に比べて記述が煩雑です。
<%= ((Boolean)request.getAttribute("isMember")).booleanValue() &&
((Integer)request.getAttribute("age")).intValue() >= 20 %>
EL式
${isMember && age >= 20}は、JSPのEL式で、isMemberがtrueであり、かつageが20以上の場合にtrueを返す論理式です。型変換が自動で行われるため、スクリプトレットよりも短く読みやすい条件判定を記述できます。
${isMember && age >= 20}
その他の演算子
empty演算子
${empty userList}は、JSPのEL式でuserListが空(nullまたは要素がない状態)かどうかを判定します。結果は真偽値(true/false)で返され、empty演算子を使うことで、nullチェックや空判定を簡潔に記述できます。
${empty userList}
null、空文字列、空のコレクション/配列の場合にtrue
三項演算子
${age >= 20 ? '成人' : '未成年'}は、JSPのEL式で三項演算子を使用し、ageが20以上なら「成人」、それ以外なら「未成年」と表示します。条件に応じて異なる値を簡潔に出力でき、スクリプトレットを使わずに分岐処理を表現できます。
${age >= 20 ? '成人' : '未成年'}
括弧による優先順位の制御
${(a + b) * c}は、JSPのEL式でaとbを加算した結果にcを掛けた値を計算し、出力します。EL式では通常の算術演算子をそのまま使用でき、括弧によって演算の優先順位を明確に指定できます。
${(a + b) * c}
EL式の暗黙オブジェクト
EL式の暗黙オブジェクト(Implicit Objects)とは、JSP内で特別な宣言や取得処理を行わなくても自動的に簡単にアクセスするで利用できるオブジェクトのことです。これらは、リクエストやセッションなどのスコープや環境情報へ簡単にアクセスするために用意されています。
主なものには、リクエストパラメータを取得するparam、スコープ内の属性にアクセスするpageScope・requestScope・sessionScope・applicationScope、クッキー情報を扱うcookie、ヘッダー情報を参照するheaderやheaderValues、コンテキスト初期化パラメータを取得するinitParamなどがあります。これらを活用することで、スクリプトレットを使わずに簡潔で可読性の高いJSPを記述できます。
| 暗黙オブジェクト | 説明 | スクリプトレット相当 | EL式例 |
|---|---|---|---|
| pageContext | PageContextオブジェクト | pageContext | ${pageContext} |
| pageScope | ページスコープの属性マップ | pageContext.getAttributes() | ${pageScope.attr} |
| requestScope | リクエストスコープの属性マップ | request.getAttribute() | ${requestScope.attr} |
| sessionScope | セッションスコープの属性マップ | session.getAttribute() | ${sessionScope.attr} |
| applicationScope | アプリケーションスコープの属性マップ | application.getAttribute() | ${applicationScope.attr} |
| param | リクエストパラメータのマップ | request.getParameter() | ${param.name} |
| paramValues | 複数値のリクエストパラメータマップ | request.getParameterValues() | ${paramValues.name[0]} |
| header | リクエストヘッダーのマップ | request.getHeader() | ${header[‘User-Agent’]} |
| headerValues | 複数値のリクエストヘッダーマップ | request.getHeaders() | ${headerValues.Accept[0]} |
| cookie | クッキーのマップ | request.getCookies() | ${cookie.JSESSIONID.value} |
| initParam | コンテキスト初期化パラメータのマップ | application.getInitParameter() | ${initParam.dbURL} |
次のコードは、スクリプトレットとEL式で同じデータを取得する方法を比較した例です。
<%-- リクエストパラメータの取得 --%>
スクリプトレット: <%= request.getParameter("username") %>
EL式: ${param.username}
<%-- セッション属性の取得 --%>
スクリプトレット: <%= session.getAttribute("currentUser") %>
EL式: ${sessionScope.currentUser}
<%-- コンテキスト初期化パラメータ --%>
スクリプトレット: <%= application.getInitParameter("maxUsers") %>
EL式: ${initParam.maxUsers}
request.getParameter("username")と${param.username}はリクエストパラメータを、session.getAttribute("currentUser")と${sessionScope.currentUser}はセッション属性を、application.getInitParameter("maxUsers")と${initParam.maxUsers}はコンテキスト初期化パラメータを取得します。EL式を使うと、スクリプトレットよりも簡潔で可読性の高い記述が可能です。
EL式のメソッド呼び出し(EL 2.2以降)
EL 2.2からはメソッド呼び出しが可能になりました。
静的メソッドの呼び出し
スクリプトレット
<%= java.util.UUID.randomUUID().toString() %>は、JSPのスクリプトレット式でUUIDクラスを使い、ランダムな一意識別子(UUID)を生成して文字列として出力します。サーバー側でユニークなIDを作成したい場合などに利用されます。
<%= java.util.UUID.randomUUID().toString() %>
EL式
${T(java.util.UUID).randomUUID()}は、Spring EL(SpEL)の構文で、java.util.UUIDクラスのrandomUUID()メソッドを呼び出して一意の識別子(UUID)を生成します。JSP標準のEL式ではなく、Spring Frameworkで拡張されたEL機能を用いることで、クラスの静的メソッドを直接呼び出せます。
${T(java.util.UUID).randomUUID()}
インスタンスメソッドの呼び出し
スクリプトレット
<%= user.getFullName(true) %>は、JSPのスクリプトレット式でuserオブジェクトのgetFullNameメソッドを呼び出し、引数にtrueを渡してその戻り値(例:フルネーム)を出力します。メソッド呼び出しを直接行える点が特徴ですが、EL式よりもコードが長くなります。
<%= user.getFullName(true) %>
EL式
${user.getFullName(true)}は、JSPのEL式でuserオブジェクトのgetFullName(true)メソッドを呼び出し、その戻り値を出力します。このようなメソッド呼び出しはEL 2.2以降でサポートされており、スクリプトレットを使わずに簡潔にメソッドを実行できます。
${user.getFullName(true)}
EL式の実践的な使用例
条件に基づくスタイルの適用
スクリプトレット
<tr class="<%= ((Integer)request.getAttribute("rowIndex")) % 2 == 0 ? "even" : "odd" %>">は、JSPのスクリプトレット式で、rowIndex属性の値が偶数ならクラス名を"even"、奇数なら"odd"に設定する処理です。表の行ごとにスタイルを切り替える際などに使用されますが、EL式に比べて記述が冗長です。
<tr class="<%= ((Integer)request.getAttribute("rowIndex")) % 2 == 0 ? "even" : "odd" %>">
EL式
<tr class="${rowIndex % 2 == 0 ? 'even' : 'odd'}">は、JSPのEL式でrowIndexが偶数なら"even"、奇数なら"odd"というクラス名を動的に設定します。三項演算子を使うことで条件分岐を簡潔に記述でき、スクリプトレットを使わずにHTML内でスタイルを切り替えることができます。
<tr class="${rowIndex % 2 == 0 ? 'even' : 'odd'}">
複雑な条件表示
スクリプトレット
このコードは、JSPのスクリプトレットを使って条件付きでadminPanel.jspを読み込む処理です。userオブジェクトが存在し、かつそのroleが"admin"であり、さらにリクエストパラメータmodeがnullまたは"simple"以外の場合にのみ、<jsp:include>で管理者パネルを表示します。条件が複雑なため、EL式やJSTLを使うとより可読性を高められます。
<% if(user != null && user.getRole().equals("admin") &&
(request.getParameter("mode") == null ||
!request.getParameter("mode").equals("simple"))) { %>
<jsp:include page="adminPanel.jsp"/>
<% } %>
EL式
このコードは、JSTL(JSP Standard Tag Library)を用いて条件付きでadminPanel.jspを読み込む例です。userが存在し、そのroleが"admin"で、さらにリクエストパラメータmodeが空または"simple"でない場合に、<jsp:include>タグで管理者パネルを表示します。スクリプトレットを使わずに条件分岐を記述できるため、可読性・保守性が高く、モダンなJSP開発で推奨される書き方です。
<c:if test="${not empty user and user.role eq 'admin'
and (empty param.mode or param.mode ne 'simple')}"><
jsp:include page="adminPanel.jsp"/>
</c:if>
コレクションの操作
スクリプトレット
このコードは、JSPのスクリプトレットを使ってproductsリストの内容を繰り返し表示する例です。
リクエストスコープからproductsを取得し、在庫数(stock)が0より大きい商品のみを表示します。行インデックスiが偶数なら"even"、奇数なら"odd"というCSSクラスを付与し、p.getName()で商品名、p.getPrice()で価格を出力します。
ただし、スクリプトレット中心の記述は可読性が低いため、EL式やJSTLの<c:forEach>タグでの書き換えが推奨されます。
<%
List<Product> products = (List<Product>)request.getAttribute("products");
for(int i=0; i<products.size(); i++) {
Product p = products.get(i);
if(p.getStock() > 0) {
%>
<div class="product <%= i % 2 == 0 ? "even" : "odd" %>">
<%= p.getName() %> - ¥<%= p.getPrice() %>
</div>
<% }} %>
EL式 + JSTL
このコードは、JSTLタグとEL式を使って商品リストを繰り返し表示する例です。<c:forEach>タグでproductsコレクションを順に処理し、var="p"で各商品オブジェクトを参照します。varStatusを利用してインデックスを取得し、偶数行と奇数行でCSSクラス(even / odd)を切り替えています。
さらに<c:if>タグでp.stock > 0の場合のみ出力し、p.nameとp.priceをEL式で簡潔に表示します。スクリプトレットを使わず、可読性と保守性の高い記述です。
<c:forEach items="${products}" var="p" varStatus="status">
<c:if test="${p.stock > 0}">
<div class="product ${status.index % 2 == 0 ? 'even' : 'odd'}">
${p.name} - ¥${p.price}
</div>
</c:if>
</c:forEach>
EL式のベストプラクティス
スクリプトレットよりEL式を優先
可能な限りスクリプトレットではなくEL式を使用
適切なスコープの使用
必要に応じて明示的にスコープを指定(${requestScope.user}など)
不要なスコープ検索を避ける
null安全を活用
nullチェックを簡潔に記述
<%-- 従来のnullチェック --%>
<%= (user != null) ? user.getName() : "" %>
<%-- EL式のnull安全 --%>
${user.name}
このコードは、スクリプトレットとEL式におけるnullチェックの違いを示した例です。
スクリプトレットでは三項演算子を使ってuserがnullでない場合のみgetName()を呼び出していますが、EL式では${user.name}のように書くだけで自動的にnull安全に処理され、NullPointerExceptionを発生させずに空文字を出力します。
複雑なロジックは避ける
EL式内で複雑な処理を行わず、ServletやJavaクラスで処理
式の可読性を考慮
長すぎる式は分割して記述
必要に応じてコメントを追加
EL式の無効化
必要に応じてEL式を無効化可能
<%@ page isELIgnored="true" %>
<%@ page isELIgnored="true" %>は、JSPページでEL式(${...}構文)を無効化するディレクティブです。これを指定すると、ページ内のEL式は評価されず、そのまま文字列として表示されます。通常はfalse(デフォルト設定)で、EL式を有効にして使用します。
EL式のデバッグ方法
直接出力して確認
Debug: ${variable}は、JSPのEL式を使って変数variableの値をデバッグ表示するシンプルな例です。スコープ内(page、request、session、application)のいずれかに存在するvariableの内容をそのまま出力し、値の確認や動作テストに便利です。
Debug: ${variable}
暗黙オブジェクトの内容確認
このコードは、EL式を使ってJSP内のスコープやオブジェクトの情報を確認するデバッグ出力の例です。${pageContext}はページ全体のコンテキスト情報、${param}はリクエストパラメータのマップ、${sessionScope}はセッションスコープ内の属性をそれぞれ表示します。これにより、実行時の変数状態やスコープの内容を簡単に確認できます。
PageContext: ${pageContext}
Request parameters: ${param}
Session attributes: ${sessionScope}
型情報の確認
Type of variable: ${variable['class'].name}は、JSPのEL式でvariableオブジェクトのクラス名(型情報)を取得して表示する例です。${variable['class']}でClassオブジェクトを参照し、.nameでその完全修飾クラス名を取得します。デバッグや型確認に便利な記述です。
Type of variable: ${variable['class'].name}
デフォルト値の使用
${empty variable ? '変数は空です' : variable}は、JSPのEL式でvariableが空(nullまたは空のコレクション・文字列など)かどうかを判定し、空なら「変数は空です」と表示し、そうでなければその値を出力します。条件分岐を簡潔に書ける便利なデバッグ表現です。
${empty variable ? '変数は空です' : variable}
EL式の制限事項
変数の宣言不可
EL式では新しい変数を宣言できません(<c:set>タグを使用)
制御フローの制限
条件分岐やループはJSTLタグと組み合わせて使用
複雑なロジックの制限
複雑なビジネスロジックには不向き
EL 2.2以前の制限
メソッド呼び出しができない(EL 2.2以前)
まとめ
EL式は、JSP開発においてスクリプトレットよりもコードを大幅に簡潔にし、HTMLとの統一感による高い可読性を実現します。また、自動的なnull処理や型変換により安全性が向上し、ロジックとプレゼンテーションを分離しやすいため、保守性にも優れています。
EL式をマスターすることで、JSPページの開発効率と品質を大幅に向上させることができます。JSTLと組み合わせることで、スクリプトレットをほとんど使用しない、モダンで保守性の高いJSPページを作成可能です。
次にカスタムタグを学ぶことで、さらに高度なテンプレート処理や独自のタグライブラリを作成するスキルを身につけることができます。EL式はそれらの技術の基盤としても重要な役割を果たしますので、基本的な使い方をしっかりと理解しておきましょう。