Expression Language Specification Kin-Man Chung, Editor: Version 3.0 Final Release
Expression Language Specification Kin-Man Chung, Editor: Version 3.0 Final Release
Oracle Corporation
www.oracle.com
(a) fully implements the Specification including all its required interfaces and
functionality;
(b) does not modify, subset, superset or otherwise extend the Licensor Name Space, or
include any public or protected packages, classes, Java interfaces, fields or methods within
the Licensor Name Space other than those required/authorized by the Specification or
Specifications being implemented; and
Expression Language 3.0 Final Release
iv
(c) passes the Technology Compatibility Kit (including satisfying the requirements of the
applicable TCK Users Guide) for such Specification ("Compliant Implementation"). In
addition, the foregoing license is expressly conditioned on your not acting outside its
scope. No license is granted hereunder for any other purpose (including, for example,
modifying the Specification, other than to the extent of your fair use rights, or distributing
the Specification to third parties). Also, no right, title, or interest in or to any trademarks,
service marks, or trade names of Specification Lead or Specification Lead's licensors is
granted hereunder. Java, and Java-related logos, marks and names are trademarks or
registered trademarks of Oracle America, Inc. in the U.S. and other countries.
3. Pass-through Conditions.
You need not include limitations (a)-(c) from the previous paragraph or any other
particular "pass through" requirements in any license You grant concerning the use of your
Independent Implementation or products derived from it. However, except with respect to
Independent Implementations (and products derived from them) that satisfy limitations
(a)-(c) from the previous paragraph, You may neither:
(a) grant or otherwise pass through to your licensees any licenses under Specification
Lead's applicable intellectual property rights; nor
(b) authorize your licensees to make any claims concerning their implementation's
compliance with the Specification in question.
a. With respect to any patent claims covered by the license granted under subparagraph 2
above that would be infringed by all technically feasible implementations of the
Specification, such license is conditioned upon your offering on fair, reasonable and non-
discriminatory terms, to any party seeking it from You, a perpetual, non-exclusive, non-
transferable, worldwide license under Your patent rights which are or would be infringed
by all technically feasible implementations of the Specification to develop, distribute and
use a Compliant Implementation.
b With respect to any patent claims owned by Specification Lead and covered by the
license granted under subparagraph 2, whether or not their infringement can be avoided in
a technically feasible manner when implementing the Specification, such license shall
terminate with respect to such claims if You initiate a claim against Specification Lead
that it has, in the course of performing its responsibilities as the Specification Lead,
induced any other entity to infringe Your patent rights.
c Also with respect to any patent claims owned by Specification Lead and covered by the
license granted under subparagraph 2 above, where the infringement of such claims can be
avoided in a technically feasible manner when implementing the Specification such
Expression Language 3.0 Final Release
v
license, with respect to such claims, shall terminate if You initiate a claim against
Specification Lead that its making, having made, using, offering to sell, selling or
importing a Compliant Implementation infringes Your patent rights.
5. Definitions.
This Agreement will terminate immediately without notice from Specification Lead if you
breach the Agreement or act outside the scope of the licenses granted above.
DISCLAIMER OF WARRANTIES
LIMITATION OF LIABILITY
REPORT
If you provide Specification Lead with any comments or suggestions concerning the
Specification ("Feedback"), you hereby: (i) agree that such Feedback is provided on a
non-proprietary and non-confidential basis, and (ii) grant Specification Lead a perpetual,
non-exclusive, worldwide, fully paid-up, irrevocable license, with the right to sublicense
through multiple levels of sublicensees, to incorporate, disclose, and use without
limitation the Feedback for any purpose.
GENERAL TERMS
Any action related to this Agreement will be governed by California law and controlling
U.S. federal law. The U.N. Convention for the International Sale of Goods and the choice
of law rules of any jurisdiction will not apply.
The Specification is subject to U.S. export control laws and may be subject to export or
import regulations in other countries. Licensee agrees to comply strictly with all such laws
and regulations and acknowledges that it has the responsibility to obtain such licenses to
export, re-export or import as may be required after delivery to Licensee.
This Agreement is the parties' entire agreement relating to its subject matter. It supersedes
all prior or contemporaneous oral or written communications, proposals, conditions,
representations and warranties and prevails over any conflicting or additional terms of any
quote, order, acknowledgment, or other communication between the parties relating to its
subject matter during the term of this Agreement. No modification to this Agreement will
be binding, unless in writing and signed by an authorized representative of each party.
Preface xvii
Historical Note xvii
Comments xviii
ix
1.5.4 Invoking method expressions 10
1.6 Operators [] and . 10
1.7 Arithmetic Operators 12
1.7.1 Binary operators - A {+,-,*} B 13
1.7.2 Binary operator - A {/,div} B 13
1.7.3 Binary operator - A {%,mod} B 14
1.7.4 Unary minus operator - -A 14
1.8 String Concatenation Operator - A += B 14
1.9 Relational Operators 14
1.9.1 A {<,>,<=,>=,lt,gt,le,ge} B 15
1.9.2 A {==,!=,eq,ne} B 15
1.10 Logical Operators 16
1.10.1 Binary operator - A {&&,||,and,or} B 16
1.10.2 Unary not operator - {!,not} A 16
1.11 Empty Operator - empty A 17
1.12 Conditional Operator - A ? B : C 17
1.13 Assignment Operator - A = B 17
1.14 Semicolon Operator - A ; B 18
1.15 Parentheses 18
1.16 Operator Precedence 18
1.17 Reserved Words 19
1.18 Functions 20
1.19 Variables 20
1.20 Lambda Expressions 20
1.21 Enums 22
1.22 Static Field and Method Reference 22
1.22.1 Access Restrictions and Imports 22
1.22.2 Imports of Packages, Classes, and Static Fields 23
1.22.3 Constructor Reference 23
1.23 Type Conversion 23
Contents xi
2.3.4.4 consumer 49
2.3.4.5 binaryOperator 49
2.3.5 filter 50
2.3.5.1 Syntax 50
2.3.5.2 Description 50
2.3.5.3 See 50
2.3.5.4 Example 50
2.3.6 map 50
2.3.6.1 Syntax 50
2.3.6.2 Description 50
2.3.6.3 See 51
2.3.6.4 Examples 51
2.3.7 flatMap 51
2.3.7.1 Syntax 51
2.3.7.2 Description 51
2.3.7.3 See 51
2.3.7.4 Examples 51
2.3.8 distinct 52
2.3.8.1 Syntax 52
2.3.8.2 Description 52
2.3.8.3 Example 52
2.3.9 sorted 52
2.3.9.1 Syntax 52
2.3.9.2 Description 52
2.3.9.3 See 53
2.3.9.4 Examples 53
2.3.10 forEach 53
2.3.10.1 Syntax 53
2.3.10.2 Description 53
2.3.10.3 See 54
2.3.10.4 Example 54
Contents xiii
2.3.18.4 Examples 58
2.3.19 min 59
2.3.19.1 Syntax 59
2.3.19.2 Description 59
2.3.19.3 See 59
2.3.20 average 59
2.3.20.1 Syntax 59
2.3.20.2 Description 59
2.3.21 sum 60
2.3.21.1 Syntax 60
2.3.21.2 Description 60
2.3.22 count 60
2.3.22.1 Syntax 60
2.3.22.2 Description 60
2.3.23 anyMatch 60
2.3.23.1 Syntax 60
2.3.23.2 Description 60
2.3.23.3 See 61
2.3.23.4 Example 61
2.3.24 allMatch 61
2.3.24.1 Syntax 61
2.3.24.2 Description 61
2.3.24.3 See 61
2.3.25 noneMatch 61
2.3.25.1 Syntax 61
2.3.25.2 Description 62
2.3.25.3 See 62
2.3.26 findFirst 62
2.3.26.1 Syntax 62
2.3.26.2 Description 62
2.3.26.3 See 62
Contents xv
xvi Expression Language Specification 3.0 • Final Release,April 29, 2013
Preface
This is the Expression Language specification version 3.0, developed by the JSR-341
(EL 3.0) expert groups under the Java Community Process. See http://www.jcp.org.
Historical Note
The EL was originally inspired by both ECMAScript and the XPath expression
languages. During its inception, the experts involved were very reluctant to design
yet another expression language and tried to use each of these languages, but they
fell short in different areas.
The JSP Standard Tag Library (JSTL) version 1.0 (based on JSP 1.2) was therefore first
to introduce an Expression Language (EL) to make it easy for page authors to access
and manipulate application data without having to master the complexity associated
with programming languages such as Java and JavaScript.
Given its success, the EL was subsequently moved into the JSP specification (JSP
2.0/JSTL 1.1), making it generally available within JSP pages (not just for attributes
of JSTL tag libraries).
JavaServer Faces 1.0 defined a standard framework for building User Interface
components, and was built on top of JSP 1.2 technology. Because JSP 1.2 technology
did not have an integrated expression language and because the JSP 2.0 EL did not
meet all of the needs of Faces, an EL variant was developed for Faces 1.0. The Faces
expert group (EG) attempted to make the language as compatible with JSP 2.0 as
possible but some differences were necessary.
It was obviously desirable to have a single, unified expression language that meets
the needs of the various web-tier technologies. The Faces and JSP EGs therefore
worked together on the specification of a unified expression language, defined in
JSR 245, and which took effect for the JSP 2.1 and Faces 1.2 releases.
xvii
The JSP/JSTL/Faces expert groups also acknowledged that the Expression
Language(EL) is useful beyond their own specifications. This specification is the first
JSR that defines the Expression Language as an independent specification, with no
dependencies on other technologies.
Typographical Conventions
Font Style Uses
Italic Emphasis, definition of term.
Comments
We are interested in improving this specification and welcome your comments and
suggestions. We have a java.net project with an issue tracker and a mailing list for
comments and discussions about this specification.
Project:
http://java.net/projects/el-spec
users@el-spec.java.net
xviii Expression Language Specification 3.0 • Proposed Final Draft - March 6, 2013
CHAPTER 1
The syntax and semantics of the Expression Language (EL) are described in this
chapter.
1.1 Overview
The EL was originally designed as a simple language to meet the needs of the
presentation layer in web applications. It features:
as well as
■ A pluggable API for resolving variable references into Java objects and for
resolving the properties applied to these Java objects
These last three features are key additions to the JSP 2.0 EL resulting from the EL
alignment work done in the JSP 2.1 and Faces 1.2 specifications.
1
EL 3.0 adds features to enable EL to be used as a stand-alone tool. It introduces APIs
for direct evaluation of EL expressions and manipulation of EL environments. It also
adds some powerful features to the language, such as the support of operations for
collection objects.
1.1.1 EL in a nutshell
The syntax is quite simple. Model objects are accessed by name. A generalized []
operator can be used to access maps, lists, arrays of objects and properties of a
JavaBeans object, and to invoke methods in a JavaBeans object; the operator can be
nested arbitrarily. The . operator can be used as a convenient shorthand for property
access when the property name follows the conventions of Java identifiers, but the
[] operator allows for more generalized access. Similarly, . operator can also be used
to invoke methods, when the method name is known, but the [] operator can be used
to invoke methods dynamically.
Relational comparisons are allowed using the standard Java relational operators.
Comparisons may be made against other values, or against boolean (for equality
comparisons only), string, integer, or floating point literals. Arithmetic operators can
be used to compute integer and floating point values. Logical operators are
available.
The EL features a flexible architecture where the resolution of model objects (and
their associated properties and methods), functions, and variables are all performed
through a pluggable API, making the EL easily adaptable to various environments.
1.2 EL Expressions
An EL expression is specified either as an eval-expression, or as a literal-expression. The
EL also supports composite expressions, where multiple EL expressions (eval-
expressions and literal-expressions) are grouped together.
For instance, by convention the JavaEE web tier specifications use the ${expr}
construct for immediate evaluation and the #{expr} construct for deferred
evaluation. This difference in delimiters points out the semantic differences between
the two expression types in the JavaEE web tier. Expressions delimited by “#{}” are
said to use “deferred evaluation” because the expression is not evaluated until its
value is needed by the system. Expressions delimited by “${}" are said to use
“immediate evaluation” because the expression is compiled when the JSP page is
compiled and it is executed when the JSP page is executed. More on this in
Section 1.2.4, “Syntax restrictions”.
For instance, all EL expressions in JSP 2.0 are evaluated by the JSP engine
immediately when the page response is rendered. They all yield rvalues.
the expression ${customer.name} is evaluated by the JSP engine and the returned
value is fed to the tag handler and converted to the type associated with the
attribute (String in this case).
Faces, on the other hand, supports a full UI component model that requires
expressions to represent more than just rvalues. It needs expressions to represent
references to data structures whose value could be assigned, as well as to represent
methods that could be invoked.
<h:form>
<h:inputText
id="email"
value="#{checkOutFormBean.email}"
size="25" maxlength="125"
validator="#{checkOutFormBean.validateEmail}"/>
</h:form>
when the form is submitted, the “apply request values” phase of Faces evaluates the
EL expression #{checkOutFormBean.email} as a reference to a data structure
whose value is set with the input parameter it is associated with in the form. The
result of the expression therefore represents a reference to a data structure, or an
lvalue, the left hand side of an assignment operation.
When that same expression is evaluated during the rendering phase, it yields the
specific value associated with the object (rvalue), just as would be the case with JSP.
The valid syntax for an lvalue is a subset of the valid syntax for an rvalue. In
particular, an lvalue can only consist of either a single variable (e.g. ${name}) or a
property resolution on some object, via the . or [] operator (e.g.
${employee.name}). Of course, an EL function or method that returns either an
object or a name can be part of an lvalue.
For instance, in JSF, a component tag also has a set of attributes for referencing
methods that can perform certain functions for the component associated with the
tag. To support these types of expressions, the EL defines method expressions (EL
class MethodExpression).
In the above example, the validator attribute uses an expression that is associated
with type MethodExpression. Just as with ValueExpressions, the evaluation of
the expression (calling the method) is deferred and can be processed by the
underlying technology at the appropriate moment within its life cycle.
A method expression shares the same syntax as an lvalue. That is, it can only consist
of either a single variable (e.g. ${name}) or a property resolution on some object, via
the . or [] operator (e.g. ${employee.name}). Information about the expected
return type and parameter types is provided at the time the method is parsed.
1.2.2 Literal-expression
A literal-expression does not use the ${expr} or #{expr} constructs, and simply
evaluates to the text of the expression, of type String. Upon evaluation, an
expected type of something other than String can be provided. Sample literal-
expressions are shown in FIGURE 1-2.
Expected
Expression Result
Type
Aloha! String Aloha!
true Boolean Boolean.TRUE
To generate literal values that include the character sequence “${" or “#{“, the
developer can choose to use a composite expression as shown here:
Alternatively, the escape characters \$ and \# can be used to escape what would
otherwise be treated as an eval-expression. Given the literal-expressions:
\${exprA}
\#{exprB}
The resulting values would again be the strings ${exprA} and #{exprB}.
Once evaluated, the resulting String is then coerced to the expected type,
according to the EL type conversion rules. A sample composite expression is shown
in FIGURE 1-3.
Expected
Expression Result
Type
Welcome Guy Lafleur to our
Welcome site
${customer.name} evaluates to a
${customer.name} to String
String which is then concatenated with the
our site
literal-expressions. No conversion
necessary.
Some APIs in EL 3.0 use only single eval-expressions, and not the composite
expressions. However, there is no lost in functionality, since a composite expression
can be specified with a single eval-expressions, by using the string concatenation
operators, introduced in EL 3.0. For instance, the composite expression
Welcome ${customer.name} to our site
can be written as
${‘Welcome ‘ += customer.name += ‘ to our site’}.
For instance, in JSP 2.1, #{} expressions are only allowed for tag attributes that
accept deferred expressions. #{expr} will generate an error if used anywhere else.
1.3 Literals
There are literals for boolean, integer, floating point, string, and null in an eval-
expression.
■ Boolean - true and false
■ Integer - As defined by the IntegerLiteral construct in Section 1.24
■ Floating point - As defined by the FloatingPointLiteral construct in
Section 1.24
The rules described below are used in resolving names and properties when
evaluating identifiers, function calls, and object properties and method calls.
One implication of the explicit search order of the identifiers is that an identifier
hides other identifiers (of the same name) that come after it in the list.
Note the above syntax allows the invocation of a lambda expression that returns
another lambda expression, which is then invoked.
The last two operators are available in both syntaxes to be consistent with XPath and
ECMAScript.
The second versions of the last 4 operators are made available to avoid having to use
entity references in XML syntax and have the exact same behavior, i.e. < behaves the
same as lt and so on.
1.9.1 A {<,>,<=,>=,lt,gt,le,ge} B
■ If A==B, if operator is <=, le, >=, or ge return true.
■ If A is null or B is null, return false
■ If A or B is BigDecimal, coerce both A and B to BigDecimal and use the return
value of A.compareTo(B).
■ If A or B is Float or Double coerce both A and B to Double apply operator
■ If A or B is BigInteger, coerce both A and B to BigInteger and use the return
value of A.compareTo(B).
■ If A or B is Byte, Short, Character, Integer, or Long coerce both A and B to
Long and apply operator
■ If A or B is String coerce both A and B to String, compare lexically
■ If A is Comparable, then:
■ If A.compareTo(B) throws exception, error.
■ Otherwise use result of A.compareTo(B)
■ If B is Comparable, then:
■ If B.compareTo(A) throws exception, error.
■ Otherwise use result of B.compareTo(A)
■ Otherwise, error
1.9.2 A {==,!=,eq,ne} B
■ If A==B, apply operator
■ If A is null or B is null return false for == or eq, true for != or ne.
The operator stops as soon as the expression can be determined, i.e., A and B and
C and D – if B is false, then only A and B is evaluated.
To evaluate empty A
■ If A is null, return true
■ Otherwise, if A is the empty string, then return true
■ Otherwise, if A is an empty array, then return true
■ Otherwise, if A is an empty Map, return true
■ Otherwise, if A is an empty Collection, return true
■ Otherwise return false
To evaluate A;B, A is first evaluated, and its value is discarded. B is then evaluated
and its value is returned.
1.15 Parentheses
Parentheses can be used to change precedence, as in: ${(a*(b+c))}
Qualified functions with a namespace prefix have precedence over the operators.
Thus the expression ${c?b:f()} is illegal because b:f() is being parsed as a
qualified function instead of part of a conditional expression. As usual, () can be
used to make the precedence explicit, e.g ${c?b:(f())}.
The symbol -> in a Lambda Expression behaves like an operator for the purpose of
ordering the operator precedence, and it has a higher precedence than the
assignment and semicolon operators. The following examples illustrates when () is
and is not needed.
v = x->x+1
x-> (a=x)
x-> c?x+1:x+2
All operators are left associative except for the ?:, =, and -> operators, which are
right associative. For instance, a=b=c is the parsed as a=(b=c), and x->y->x+y is
parsed as x->(y->x+y).
Note that many of these words are not in the language now, but they may be in the
future, so developers must avoid using these words.
EL functions are mapped, resolved and bound at parse time. It is the responsibility
of the FunctionMapper class to provide the mapping of namespace-qualified
functions to static methods of specific classes when expressions are created. If no
FunctionMapper is provided (by passing in null), functions are disabled.
1.19 Variables
Just like FunctionMapper provides a flexible mechanism to add functions to the
EL, VariableMapper provides a flexible mechanism to support the notion of EL
variables. An EL variable does not directly refer to a model object that can then be
resolved by an ELResolver. Instead, an EL variable refers to an EL expression. The
evaluation of that EL expression yields the value associated with the EL variable.
EL variables are mapped, resolved and bound at parse time. It is the responsibility of
the VariableMapper class to provide the mapping of EL variables to
ValueExpressions when expressions are created. If no VariableMapper is
provided (by passing in null), variable mapping is disabled.
The identifiers to the left of -> are lambda parameters. The parenthesis is optional if
and only if there is one parameter.
When a lambda expression is invoked, the expression in the body is evaluated, with
its formal parameters replaced by the arguments supplied at the invocation. The
number of arguments must be equal to or more than the number the formal
parameters. Any extra arguments are ignored.
The scope of a lambda argument is the body of the lambda expression. A lambda
argument hides other EL variables, identifiers or arguments of the nesting lambda
expressions, of the same name.
Note that in the case of nested lambda expressions where the body of the inner
lambda expression contains references to parameters of outer lambda expressions,
such as
■ x->y->x+y
the scope of the outer lambda parameters extends to cover the inner body. For
instance, with the above example, the argument x must be in scope when x+y is
evaluated, even though the body of the outer lambda expression has already been
executed.
An enum constant is a public static field, so the same syntax can be used to refer to
an enum constant, like the following:
RoundingMode.FLOOR
3. Except for classes with java.lang.* package names, a class has to be explicitly
imported before its static fields or methods can be referenced.
A static field can also be imported statically. A statically imported static field can be
referenced by the field name, without the classname.
The imports of packages, classes, and static fields are handled by the
ImportHandler in the ELContext.
denotes the invocation of the constructor of the class with the supplied arguments.
The same restrictions (the class must be public and has already been imported) for
static methods apply to the constructor calls.
During expression evaluations, the custom type converters are first selected and
applied. If there is no custom type converter for the conversion, the default
conversions specified in the following sections are used.
For example, if coercing an int to a String, “box” the int into an Integer and
apply the rule for coercing an Integer to a String. Or if coercing a String to a
double, apply the rule for coercing a String to a Double, then “unbox” the
resulting Double, making sure the resulting Double isn’t actually null.
■ If N is BigDecimal,
■ If N is BigInteger then:
■ If new BigInteger(A) throws an exception then error.
/* == Option Declaration == */
options
/*
* LiteralExpression
* Non-EL Expression blocks
*/
void LiteralExpression() #LiteralExpression : { Token t = null; }
{
t=<LITERAL_EXPRESSION> { jjtThis.setImage(t.image); }
}
/*
* DeferredExpression
* #{..} Expressions
*/
void DeferredExpression() #DeferredExpression : {}
{
<START_DEFERRED_EXPRESSION> Expression() <RCURL>
}
/*
* DynamicExpression
* ${..} Expressions
*/
void DynamicExpression() #DynamicExpression : {}
{
<START_DYNAMIC_EXPRESSION> Expression() <RCURL>
}
/*
* Expression
* EL Expression Language Root
*/
/*
* SemiColon
*/
void SemiColon() : {}
{
Assignment() (<SEMICOLON> Assignment() #SemiColon(2) )*
}
/*
* Assignment
* For '=', right associatve, then LambdaExpression or Choice or
Assignment
*/
void Assignment() : {}
{
LOOKAHEAD(3) LambdaExpression() |
Choice() (<ASSIGN> Assignment() #Assign(2) )?
}
/*
* LambdaExpression
*/
void LambdaExpression() #LambdaExpression : {}
{
LambdaParameters() <ARROW>
(LOOKAHEAD(3) LambdaExpression() | Choice() )
}
/*
* Choice
* For Choice markup a ? b : c, right associative
*/
void Choice() : {}
{
Or() (<QUESTIONMARK> Choice() <COLON> Choice() #Choice(3))?
}
/*
* Or
* For 'or' '||', then And
*/
void Or() : {}
{
And() ((<OR0>|<OR1>) And() #Or(2))*
}
/*
* And
* For 'and' '&&', then Equality
*/
void And() : {}
{
Equality() ((<AND0>|<AND1>) Equality() #And(2))*
}
/*
* Equality
* For '==' 'eq' '!=' 'ne', then Compare
*/
void Equality() : {}
{
Compare()
/*
* Compare
* For a bunch of them, then Math
*/
void Compare() : {}
{
Concatenation()
(
((<LT0>|<LT1>) Concatenation() #LessThan(2))
|
((<GT0>|<GT1>) Concatenation() #GreaterThan(2))
|
((<LE0>|<LE1>) Concatenation() #LessThanEqual(2))
|
((<GE0>|<GE1>) Concatenation() #GreaterThanEqual(2))
)*
}
/*
* Concatenation
* For 'cat', then Math()
*/
void Concatenation() : {}
{
Math() ( <CONCAT> Math() #Concat(2) )*
}
/*
* Math
* For '+' '-', then Multiplication
/*
* Unary
* For '-' '!' 'not' 'empty', then Value
*/
void Unary() : {}
{
<MINUS> Unary() #Negative
|
(<NOT0>|<NOT1>) Unary() #Not
|
/*
* ValuePrefix
* For Literals, Variables, and Functions
*/
void ValuePrefix() : {}
{
Literal() | NonLiteral()
}
/*
* ValueSuffix
* Either dot or bracket notation
*/
void ValueSuffix() : {}
{
DotSuffix() | BracketSuffix()
}
/*
* DotSuffix
* Dot Property and Dot Method
*/
void DotSuffix() #DotSuffix : { Token t = null; }
/*
* Parenthesized Lambda Expression, with optional invokation
*/
void LambdaExpressionOrCall() #LambdaExpression : {}
{
<LPAREN>
LambdaParameters() <ARROW>
(LOOKAHEAD(3) LambdaExpression() | Choice() )
<RPAREN>
(MethodArguments())*
}
/*
* NonLiteral
* For Grouped Operations, Identifiers, and Functions
/*
* Identifier
* Java Language Identifier
*/
void Identifier() #Identifier : { Token t = null; }
{
<DEFAULT> TOKEN :
{
< LITERAL_EXPRESSION:
((~["\\", "$", "#"])
| ("\\" ("\\" | "$" | "#"))
| ("$" ~["{", "$"])
| ("#" ~["{", "#"])
)+
| "$"
| "#"
>
|
< START_DYNAMIC_EXPRESSION: "${" > {stack.push(DEFAULT);}:
IN_EXPRESSION
|
< START_DEFERRED_EXPRESSION: "#{" > {stack.push(DEFAULT);}:
IN_EXPRESSION
}
Notes
■ * = 0 or more, + = 1 or more, ? = 0 or 1.
■ An identifier is constrained to be a Java identifier - e.g., no -, no /, etc.
■ A String only recognizes a limited set of escape sequences, and \ may not
appear unescaped.
This chapter describes how collection objects and literals can be constructed in the
EL expression, and how collection objects can be manipulated and processed by
applying operations in a pipeline.
2.1 Overview
To provide support for collection objects, EL includes syntaxes for constructing sets,
lists, and maps dynamically. Any EL expressions, not just literals, can be used in the
construction.
EL also includes a set of operations that can be applied on collections. By design, the
methods supporting these operations have names and semantics very similar to
those in Java SE 8 libraries. Since EL and Java have different syntaxes and
capabilities, they are not identical, but they are similar enough that users should
have no problem switching from one to the other.
Since the methods supporting the collection operations do not exist in Java SE 7,
they are implemented in the Expression Language with ELResolvers. In an EL
expression, collection operations are carried out by invoking methods, and no
special syntaxes are introduced for them. Strictly speaking, these operations are not
part of the expression language, and can be taken as examples of what can be
achieved with the expression language. The specification specifies the syntaxes and
behaviors of a standard set of collection operations. However, an user can easily add,
extend and modify the behavior of the operations by providing customized
ELResolvers.
Compared to Java SE 8, the collection support in EL has a much smaller and simpler
scope. Although EL does not disallow collections of infinite size, it works best when
the collection objects are created in memory, with known sizes. It also does not
43
address the performance issue in a multi-threaded environment, and does not
provide explicit controls for evaluating collection operations in parallel. The future
version of EL will likely include functionalities from Java SE 8, when it is released.
2.2.1.1 Syntax
SetData := ‘{‘ DataList ‘}’
DataList := (expression (‘,’ expression)* )?
2.2.1.2 Example
{1, 2, 3}
2.2.2.2 Example
[1, "two", [foo, bar]]
2.2.3.1 Syntax
Map := '{' MapEntries '}'
MapEntries := (MapEntry (',' MapEntry)* )?
MapEntry := expression ':' expression
2.2.3.2 Example
{"one":1, "two":2, "three":3}
To obtain a Stream from a Map, the collection view of a Map, such as MapEntry can
be used as the source of Stream.
Some operations return another Stream, which allows other operations. Therefore
the operations can be chained together to form a pipeline. For example, to get a list
of titles of history books, one can write in EL:
The execution of a pipeline only begins when the terminal operation starts its
execution. Most of the intermediate operations are evaluated lazily: they only yield
as many elements in the stream as are required by the downstream operations.
Because of this, they need not keep intermediate results of the operations. For
instance, the filter operation does not keep a collection of the filtered elements.
A notable exception is the sorted operation, since all elements are needed for
sorting.
The specification specifies the behavior of the operations in a pipeline, and does not
specify the implementation of a pipeline. The operations must not modify the source
collection. The user must also make sure that the source collection is not modified
externally during the execution of the pipeline, otherwise the behavior of the
collection operations will be undefined.
The behavior of the operations are undefined if the collection contains null elements.
Null elements in a collection should be removed by a filter to obtain consistent
results.
The source stream in a pipeline that has already started its execution cannot be used
in another pipeline, otherwise the behavior is undefined.
Some methods have optional parameters. The declarations of the methods with all
possible combinations of the parameters are listed in the syntax sections, as if they
are overloaded. Any null parameter will result in a NullPointerException at
run-time.
Some of the parameters are lambda expressions, also known as functions. A lambda
expression can have its own parameters and can return a value. To describe the
parameter types and the return type of a lambda expression, the following is an
example of the notation that is used.
(p1,p2)->returnT
From this we know that the source object is a Stream of S, and the return object is
also a Stream, of the same type. The operator takes a predicate function (lambda
expression) as an argument. The argument of the function is an element of the
source, and the function returns a boolean.
The generic types in the declaration are used only to help the readers to identify the
type relationships among various parts of the declaration, and do not have the same
meaning as used in the Java language. At runtime, EL deals with Objects, and does
not track generic types.
2.3.3.2 Optional
An Optional is used to represent a value that may not exist. Instead of using null
as a default value, the use of Optional allows the user to specify a default.
The value held by the Optional is processed by the function consumer if it is not
empty. See also Section 2.3.4.4 “consumer” on page 2-49.
■ T orElse(T other)
Returns the value held by the Optional, or the value other if the Optional is
empty.
■ T orElseGet((()->T) other)
Returns the value held by the Optional, or the value returned by the lambda
expression other if the Optional is empty.
2.3.4 Functions
Some operations takes functions (lambda expressions) as parameters. Again, we
used the notion
(arg1Type, ...)->returnType
This function takes the input argument, usually the element of the source stream,
and determines if it satisfies some criteria.
2.3.4.2 mapper
■ S -> R
This function maps, or transforms the input argument, usually the element of the
source stream, to the result.
2.3.4.3 comparator
■ (S, S) -> int
This function compares two arguments, usually the elements of the source stream,
and returns a negative integer, zero, or a positive integer, if the first argument is
respectively less than, equal to, or greater than the second argument.
2.3.4.4 consumer
■ S -> void
This function processes the input argument, usually the element of the source
stream, and returns nothing.
2.3.4.5 binaryOperator
■ (S, S) -> S
This function applies a binary operation to the input arguments, and returns the
result. The first argument is usually an internal accumulator value, and the second
argument is usually the element of the source stream.
2.3.5.1 Syntax
Stream<S> Stream<S>.filter((S->boolean) predicate)
2.3.5.2 Description
This method produces a stream containing the source stream elements for which the
predicate function returns true. The argument of predicate function
represents the element to test.
2.3.5.3 See
Section 2.3.4.1 “predicate” on page 2-49
2.3.5.4 Example
To find the products whose price is greater than or equal to 10:
products.stream().filter(p->p.unitPrice >= 10).toList()
2.3.6 map
2.3.6.1 Syntax
Stream<R> Stream<S>.map((S->R) mapper)
2.3.6.2 Description
This method produces a stream by applying the mapper function to the elements of
the source stream. The argument of mapper function represents the element to
process, and the result of the mapper function represents the element of the
resulting Stream.
2.3.6.4 Examples
■ To get the list of the names of all products:
products.stream().map(p->p.name).toList()
■ To creates a list of product names and prices for products with a price greater
than or equal to 10:
products.stream().filter(p->p.unitPrice >= 10).
.map(p->[p.name, p.unitPrice])
.toList()
2.3.7 flatMap
2.3.7.1 Syntax
Stream<R> Stream<S>.flatMap((S->Stream<R>) mapper)
2.3.7.2 Description
This method produces a stream by mapping each of the source elements to another
stream and then concatenating the mapped streams. If the mapper function does not
return a Stream, the behavior is undefined.
2.3.7.3 See
Section 2.3.4.2 “mapper” on page 2-49
2.3.7.4 Examples
■ To list all orders of US customers:
customers.stream().filter(c->c.country == 'USA')
.flatMap(c->c.orders.stream())
.toList()
■ To obtain a list of alphabets used in a list of words:
2.3.8 distinct
2.3.8.1 Syntax
Stream<S> Stream<S>.distinct()
2.3.8.2 Description
This method produces a stream containing the elements of the source stream that are
distinct, according to Object.equals.
2.3.8.3 Example
To remove the duplicate element b:
['a', 'b', 'b', 'c'].stream().distinct().toArray()
2.3.9 sorted
2.3.9.1 Syntax
Stream<S> Stream<S>.sorted()
Stream<S> Stream<S>.sorted(((p,q)->int) comparator)
2.3.9.2 Description
This method produces a stream containing the elements of the source stream in
sorted order. If no comparator is specified, the elements are sorted in natural order.
The behavior is undefined if no comparator is specified, and the elements do not
implement java.lang.Comparable. If a comparator is specified, the elements
are sorted with the provided comparator.
2.3.9.3 See
Section 2.3.4.3 “comparator” on page 2-49
2.3.9.4 Examples
■ To sort a list of integers
[1,3,2,4].stream().sorted().toList()
■ To sort a list of integers in reversed order
[1,3,2,4].stream().sorted((i,j)->j-i).List()
■ To sort a list of words in the order of word length; and then for words of the same
length, in alphabetical order:
words.stream().sorted(
(s,t)->(s.length()==t.length()? s.compareTo(t)
: s.length() - t.length()))
.toLst()
■ To sort the products by name:
products.stream().sorted(
(p,q)->p.name.compareTo(p.name)).toList()
2.3.10 forEach
2.3.10.1 Syntax
Object stream<S>.forEach(((S)->void)consumer)
2.3.10.2 Description
This method invokes the consumer function for each element in the source stream.
2.3.10.4 Example
To print a list of customer names:
customers.stream().forEach(c->printer.print(c.name))
2.3.11 peek
2.3.11.1 Syntax
Stream<S> Stream<S>.peek(((S)->void)consumer)
2.3.11.2 Description
This method produces a stream containing the elements of the source stream, and
invokes the consumer function for each element in the stream. The primary purpose
of this method is for debugging, where one can take a peek at the elements in the
stream at the place where this method is inserted.
2.3.11.3 See
Section 2.3.4.4 “consumer” on page 2-49
2.3.11.4 Example
To print the a list of integer before and after a filter:
[1,2,3,4,5].stream().peek(i->print(i))
.filter(i-> i%2 == 0)
.peek(i->print(i))
.toList()
2.3.12.1 Syntax
Iterator<S> Stream<S>.iterator()
2.3.12.2 Description
This method returns an iterator for the source stream, suitable for use in Java codes.
2.3.13 limit
2.3.13.1 Syntax
Stream<S> Stream<S>.limit(Number count)
2.3.13.2 Description
This method produces a stream containing the first count number of elements of
the source stream.
If count is greater than the number of source elements, all the elements are included
in the returned stream. If the count is less than or equal to zero, an empty stream is
returned.
2.3.13.3 Example
To list the 3 most expensive products:
products.stream().sorted(p->p.unitPrice)
.limit(3)
.toList()
2.3.14.1 Syntax
Stream<S> Stream<S>.substream(Number start)
Stream<S> Stream<S>.substream(Number start, Number end)
2.3.14.2 Description
This method produces a stream containing the source elements, skipping the first
start elements, and including the rest of the elements in the stream if end is not
specified, or the next (end - start) elements in the stream if end is specified.
If the elements in the source stream has fewer than start elements, nothing is
included. If start is less than or equal to zero, no elements are skipped.
2.3.14.3 Example
The example
[1,2,3,4,5].stream().substream(2,4).toArray()
2.3.15 toArray
2.3.15.1 Syntax
S[] Stream<S>.toArray()
2.3.15.2 Description
This method returns an array containing the elements of the source stream.
2.3.16.1 Syntax
List Stream<S>.toList()
2.3.16.2 Description
This method returns a List containing the elements of the source stream.
2.3.17 reduce
2.3.17.1 Syntax
Optional<S> Stream<S>.reduce(((S,S)->S) binaryOperator)
S Stream<S>.reduce(S seed, ((S,S)->S) binaryOperator))
2.3.17.2 Description
The method with a seed value starts by assigning the seed value to an internal
accumulator. Then for each of the elements in the source stream, the next
accumulator value is computed, by invoking the binaryOperator function, with
the current accumulator value as the first argument and the current element as the
second argument. The final accumulator value is returned.
The method without a seed value uses the first element of the source elements as
the seed value. If the source stream is empty, an empty Optional is returned,
otherwise an Optional with the final accumulator value is returned.
2.3.17.3 See
Section 2.3.3.2 “Optional” on page 2-48
2.3.18 max
2.3.18.1 Syntax
Optional<S> Stream<S>.max()
Optional<S> Stream<S>.max(((p,q)->int) comparator)
2.3.18.2 Description
This method computes the maximum of the elements in the source stream. If the
comparator function is specified, it is used for comparisons. If no comparator
function is specified, the elements themselves are compared, and must implement
Comparable, otherwise an ELException is thrown.
2.3.18.3 See
Section 2.3.4.3 “comparator” on page 2-49
2.3.18.4 Examples
■ To find tallest student in a class:
students.stream().max((p,q)->p.height-q.height)
■ To find the maximum height of the students in a class:
students.stream().map(s->s.height).max()
2.3.19.1 Syntax
Optional<S> Stream<S>.min()
Optional<S> Stream<S>.min(((p,q)->int) comparator)
2.3.19.2 Description
This method computes the minimum of the elements in the source stream. If the
comparator function is specified, it is used for comparisons. If no comparator
function is specified, the elements themselves are compared, and must implement
Comparable, otherwise an ELException is thrown.
2.3.19.3 See
Section 2.3.4.3 “comparator” on page 2-49
2.3.20 average
2.3.20.1 Syntax
Optional<S> Stream<S>.average()
2.3.20.2 Description
This method computes the average of all elements in the source stream by first
computes the sum of the elements and then divides the sum by the number of
elements. The elements are coerced to Number types according to Section 1.23.3
during the computation.
2.3.21.1 Syntax
Number Stream<S>.sum()
2.3.21.2 Description
This method computes the sum of all elements in the source stream. The elements
are coerced to Number types according to Section 1.23.3 during the computation.
2.3.22 count
2.3.22.1 Syntax
Long Stream<S>.count()
2.3.22.2 Description
This method returns the count of elements in the source stream.
2.3.23 anyMatch
2.3.23.1 Syntax
Optional<boolean> Stream<S>.anyMatch((S->boolean) predicate)
2.3.23.2 Description
This method returns an Optional of true if any element in the source stream
satisfies the test given by the predicate. It returns an empty Optional if the
stream is empty.
2.3.23.4 Example
To determine if the list of integers contains any negative numbers:
integers.stream().anyMatch(i->i<0).orElse(false)
Note the use of orElse to set a default value for the empty list.
2.3.24 allMatch
2.3.24.1 Syntax
Optional<boolean> Stream<S>.allMatch((S->boolean) predicate)
2.3.24.2 Description
This method returns an Optional of true if all elements in the source stream
satisfy the test given by the predicate. It returns an empty Optional if the stream
is empty.
2.3.24.3 See
Section 2.3.4.1 “predicate” on page 2-49
2.3.25 noneMatch
2.3.25.1 Syntax
Optional<boolean> Stream<S>.noneMatch((S->boolean) predicate)
2.3.25.3 See
Section 2.3.4.1 “predicate” on page 2-49
2.3.26 findFirst
2.3.26.1 Syntax
Optional<S> Stream<S>.findFirst()
2.3.26.2 Description
This method returns an Optional containing the first element in the stream, or an
empty Optional if the stream is empty.
2.3.26.3 See
Section 2.3.3.2 “Optional” on page 2-48
Changes
This appendix lists the changes in the EL specification. This appendix is non-
normative.
63
■ Added Chapter 2 “Operations on Collection Objects”.
■ Added 1.8, String concatenation operator.
■ Added 1.13, Assignment operator.
■ Added 1.14, Semi-colon operator.
■ Added 1.20 Lambda Expression.
■ Added 1.22 Static Field and Methods.
■ Added T and cat to 1.17 Reserved words.
■ Modified 1.16 Operator precedence.
■ Modified coercion rule from nulls to non-primitive types.
■ Many changes to the javadoc API.
Chapter A Changes 65
A.7 Changes between Final Release and
Proposed Final Draft 2
Added support for enumerated data types. Coercions and comparisons were
updated to include enumerated type types.
javax.el.ResourceBundleELResolver
■ New ELResolver class added to support easy access to localized messages.
Generics
■ Since JSP 2.1 requires J2SE 5.0, we’ve modified the APIs that can take
advantage of generics. These include:
ExpressionFactory:createValueExpression(),
ExpressionFactory:createMethodExpression(),
ExpressionFactory:coerceToType(), ELResolver:getType(),
ELResolver:getCommonPropertyType(), MethodInfo:MethodInfo(),
MethodInfo.getReturnType(), MethodInfo:getParamTypes()
javax.el.ELException
■ ElException now extends RuntimeException instead of Exception.
■ Method getRootCause() has been removed in favor of
Throwable.getCause().
javax.el.ExpressionFactory
■ Creation methods now use ELContext instead of FunctionMapper (see EL
Variables above).
■ Added method coerceToType(). See issue 132 at jsp-spec-public.dev.java.net.
javax.el.MethodExpression
■ invoke() must unwrap an InvocationTargetExceptions before re-throwing
as an ELException.
Chapter A Changes 67
Section 1.6 - Operators [] and .
■ PropertyNotFoundException is now thrown instead of
NullPointerException when this is the last property being resolved and we’re
dealing with an lvalue that is null.
To solve this issue, the specification of MethodExpression has been expanded to also
support String literal-expressions. Changes have been made to:
■ Section 1.2.2
■ ExpressionFactory.createMethodExpression()
■ javax.el.MethodExpression:invoke()