JavaFX Script is a statically typed language, in which the type is associated with the variable and not the value. Hence it is capable of detecting type errors at compile time and thus allows many type errors to be caught early in the development cycle. Static type checkers evaluate only the type information that can be determined at compile time, but they are able to verify that the checked conditions hold for all possible executions of the program, which eliminates the need to repeat type checks every time the program is executed. This makes execution and storage more efficient and optimized.
Variable declarations in JavaFX Script are similar to those in Java itself. JavaFX Script is a case-sensitive language, which means that an identifier written in uppercase is not equivalent to another one with the same name but written in lowercase.
In JavaFX Script every variable, function, and expression (if
statement, loop, and so on) has a type, which is determined from the context of how it has been used. JavaFX Script data types consist of an element specifier and a cardinality.
The element specifier tells what type of data a variable holds. Listing 3-1 presents two examples.
Here the variable x
holds a value of the Integer type, and the variable pi
holds a value of the Number (or floating-point) type of data.
The cardinality of a data type determines how many elements can be held in a JavaFX Script type. Cardinality will be covered later in this chapter.
We can also define a variable using def
as well. With def
, variables are defined once and never assigned to again during their lifetime. Variables declared using var
, however, can be assigned a new definition anytime. Listing 3-2 shows an example.
Example 3.2. Examples of def declarations
def pi = 3.14; def v1 = bind (x + y); // bind is a keyword and it will be covered in detail in the Binding chapter.
Bind is a keyword and will be covered in detail in Chapter 11, "Binding."
In this example, the value of pi
is a going to be a constant, so it is wise to declare it as def
. Similarly, the value of v1
is derived from x, y
and cannot be assigned directly, since it is bound. Hence it is a better programming practice to declare v1
as def
instead of var
. Remember that the value of v1
will change when the x
or y
value changes, but the definition of v1
never changes (the summation of x + y
, in this case).
It is important for the programmer to choose between var
and def
when declaring variables, and using def
at appropriate places will reap huge benefits in memory and performance because the compiler knows in advance that the value defined by def
is to remain constant, and it optimizes the way that value will be stored and used during the program lifecycle.
A valid variable name is a sequence of one or more letters, digits, or underscore characters (_). JavaFX Script uses the same rules as Java to name the variables:
No special character can be part of a variable name. Only letters, digits, and single underscore characters are valid.
A variable name must always begin with a letter or an underline character (_).
A variable name can't be a reserved word or keyword.
When choosing a name for your variables, use full words instead of cryptic abbreviations. Doing so will make your code easier to read and understand.
Table 3-1 lists the standard JavaFX Script reserved keywords.
Table 3.1. JavaFX Script Reserved Keywords
abstract | after | and | as | assert | at | attribute | bind | bound | break |
by | catch | class | continue | delete | do | else | exclusive | extends | false |
finally | first | for | from | function | if | import | in | indexof | init |
insert | into | inverse | last | lazy | let | new | not | null | on |
or | override | package | postinit | private | protected | public | readonly | replace | return |
reverse | sizeof | static | step | super | then | this | throw | true | try |
tween | typeof | var | where | while | with |
Use one of the following syntax forms to declare a variable:
var variableName : <data type>;
or
var variableName : <data type> = initialization;
or
var variableName - initialization;
var
is a keyword, which is used to declaring a variable. A variable's type declaration is optional. If the type is omitted from a variable declaration statement, the compiler infers or derives the data type of that variable from the value assigned to it; this is called type inference. A variable that is not assigned an initial value will be assigned a default value that varies based on the data type. See "Default Values for Data Types" later in this chapter for a complete list of default values.
Once the compiler derives the type from the given data, the data type for that variable is set permanently and cannot be changed later, because JavaFX Script is a statically typed language. By contrast, in a dynamically typed language like JavaScript, the type can change over a variable's lifetime.
There are five data types available in JavaFX Script:
Integer
Number
Boolean
Duration
A String is a set of characters enclosed within either single or double quotes. You declare it with one of the following syntax forms:
var variableName
:String;
var variableName
: String = "initial Value
";// a string is initialized with double quotes
var variableName
= 'initial Value
';// string is initialized with single quotes or double quotes, type is inferred
Listing 3-3 shows examples of each type.
Example 3.3. Examples of String declarations
var str1 : String ='JavaFX'; // String data type declaration var str2 : String = "JavaFX"; // String data type declaration var str3 = "JavaFX"; // String inferred type println(" str1 = { str1 } "); println(' str2 = { str2 }"); println(" str3 = {str3 } ");
The println
statements produce the following output:
JavaFX JavaFX JavaFX
The code in Listing 3-3 demonstrates String data type declarations, along with the declaration of a string inferred type. The first three lines all declare a string data type and initialize its value. The first two examples explicitly define the data type; in the third, the compiler will infer it automatically from the value assigned to the variable.
The String data type in JavaFX Script maps to the String class in Java. This means that we call the methods of Java's String class in JavaFX Script. Listing 3-4 demonstrates how this works.
Example 3.4. Calling methods of the Java String class
var str : String = "Scripting 'JavaFX' Language"; println("str {str}"); // ostr = Scripting 'JavaFX' Language // find the length of the string. println("str length = {str.length() }"); // str length = 18 // convert the string to uppercase var upperCaseString = str.toUpperCase(); // UpperCase = SCRIPTING LANGUAGE println("UpperCase = {upperCaseString}"); // convert the string to lowercase. var lowerCaseString = upperCaseString.toLowerCase(); // lowerCase = scripting language println("lowerCase = {lowerCaseString}"); // get the substring var subString = str.substring(10); // subString = Language println(" subString = {subString}");
This code produces the following output:
str = Scripting 'JavaFX' Language str length = 18 UpperCase = SCRIPTING LANGUAGE lowerCase = scripting language subString = Language
Listing 3-4 demonstrates that the JavaFX Script String data type can be used to invoke Java String class methods. Substring
, length
, toLowerCase()
, and toUpperCase()
are methods from the Java.lang.String
class that are accessed using JavaFX Script String types.
Strings in JavaFX Script are immutable, as in Java; this means you cannot change the characters in the string. For example, the method str.toLowercase()
appears to modify the string, but it actually returns a new string object, leaving the original one unchanged.
One notable difference in JavaFX Script is that you can include two single quotes with a double-quoted string and two double quotes within a single-quoted string as follows:
var s: String = "JavaFX is a 'cool' technology"; var s1: String = 'JavaFX is a "cool" technology';
The single and double quoted text used within the string will be treated as-is and you will see quote characters when printing the values as well. Another pair of special characters that are treated differently within the string are the curly braces. Anything specified between curly braces within a string is treated as an expression. Listing 3-5 presents an example.
Example 3.5. Examples of quotes and braces with strings
var i: Integer = 10; var j: Integer = 10; println("Value of 'i + j' is: {i + j}");
This code displays the following output:
Value of 'i + j' is: 20
In this example, {i + j}
is treated as an expression and evaluated, and the result of the evaluation is converted to String and replaces {i + j}
.
However, these are special cases, and to include other special characters, such as the backslash or line feed, you will have to use the escape character, discussed next.
The character and string escape sequences allow for the representation of some nonprinting characters. Table 3-2 lists some of the common escape characters.
Table 3.2. Common Escape Sequences
| tab |
| new line |
backspace | |
| form feed |
| carriage return |
| double quote |
| single quote |
| backslash |
As an example, the code in Listing 3-6 will include a new line in the given string.
Example 3.6. Using the escape character for a new line
var escStr: String = "JavaFX is cool"; println("String with esc character: {escStr}");
This code produces the following output:
String with esc character: JavaFX is cool
An Integer value represents a number with no decimal or fractional part—a whole number. An Integer can be either positive or negative.
The following snippet shows how to get the minimum and maximum value that an Integer primitive data type can hold.
var intMin: Integer = java.lang.Integer.MIN_VALUE; println("intMin = {intMin}"); var intMax: Integer = java.lang.Integer.MAX_VALUE; println("intMax = {intMax}");
It produces the following output:
intMin = −2147483648 intMax = 2147483647
From this example, it is clear that the JavaFX Script Integer primitive data type maps to the java.lang.Integer
class in Java, which means that we can use the methods in java.lang.Integer
on the JavaFX Script Integer data type. An Integer literal may be expressed in decimal (base 10), hexadecimal (base 16), or octal (base 8). Let us see each of these numeric representations in detail.
A decimal number is either the single ASCII character 0, representing the integer zero, or an ASCII digit from 1 to 9, optionally followed by one or more ASCII digits from 0 to 9, representing a positive integer.
Following are the decimal numbers:
0 1 2 3 4 5 6 7 8 9
Here are two examples:
var width : Integer = 150; var translat eX: Integer = −15;
A hexadecimal number consists of the leading ASCII characters 0x or 0X followed by one or more ASCII hexadecimal digits. It may be positive, zero, or negative. Hexadecimal digits with values 10 through 15 are represented by the ASCII letters a through f or A through F. The letters may be uppercase or lowercase.
Following are the hexadecimal numerals:
0 1 2 3 4 5 6 7 8 9 A B C D E F
or
0 1 2 3 4 5 6 7 8 9 a b c d e f
Here is an example:
var xValue : Integer = 0X12A;
An octal number consists of the ASCII digit 0 followed by one or more of the ASCII digits 0 through 7 and can represent a positive, zero, or negative integer.
Following are the hexadecimal numbers:
0 1 2 3 4 5 6 7
Here is an example:
var no : Number = 05;
Octal numerals always consist of two or more digits. 0 is always considered to be a decimal number; but in practice, the numbers 0, 00, and 0x0 all represent exactly the same integer value.
Values of the Number data type are also known as real or floating-point numbers. This data type is used when evaluating any expression that requires fractional precision. A Number can contain either a decimal point, an e (uppercase or lowercase), which is used to represent "ten to the power of" in scientific notation, or both. The exponent part is an e or E followed by an integer, which can be signed (preceded by either + or −). Listing 3-7 presents an example.
Example 3.7. Examples of floating-point numbers
var pi : Number = 3.142; // pi is a floating point no. var num : Number = 10; // 10 will be promoted to 10.0 var num1 = 10; // Type inferred as Integer
The first statement declares a Number variable pi
, which holds the decimal number 3.142. The second statement declares a Number variable num
, which holds the number 10. But after executing the second statement the variable value becomes 10.0, since the data is promoted from Integer to Number. The third line does not specify the data type but assigns a value of 10. Hence the data type for num1
will be automatically inferred by the compiler as Integer.
Listing 3-8 demonstrates different ways of declaring a Number.
Example 3.8. Examples of Number declarations
// declare a variable with out initial value var a : Number ; println("a {a}"); // a 0.0 // declare a variable with the inital value var pi = 3.142; println("pi = {pi}"); // pi = 3.142 // declare a variable with intial value expressed in scientific notation or expontential form. var b : Number = 10e2; println("b = {b}"); // b = 1000.0
These declarations produce the following output:
a 0.0 pi = 3.142 b = 1000.0
The code in Listing 3-8 demonstrates different ways of declaring a Number variable. The first example declares a variable of Number type but does not initialize it. Hence a default value of 0.0 would be assigned. The second example initializes the variable but does not define the data type. The compiler would in this case automatically infer the type as Number. Finally, the third example declares a Number variable and initializes it with an exponent decimal value.
Listing 3-9 demonstrates the range of the Number data type.
Example 3.9. Example to print the minimum and maximum value of Number data type
var numMin: Number = java.lang.Double.MIN_VALUE; println("Minimum value of Number data type = {numMin}"); var numMax: Number = java.lang.Double.MAX_VALUE; println("Maximum value of Number data type = {numMax}");
This code produces the following output:
Minimum value of Number data type = 4.9E-324 Maximum value of Number data type = 1.7976931348623157E308
A Boolean variable has two states, true and false, which are appropriately represented by the keywords true
and false
. The Boolean variable, therefore, represents the state of something that can have only one of two values. These values are typically used as checkpoints for determining whether to take a certain action. Listing 3-10 demonstrates how to use the Boolean data type.
Example 3.10. Examples of Boolean variables
var flag : Boolean = true; if(flag) { println(This line will be printed on the console); }
The if
conditional statement is covered in depth in Chapter 4, "Expressions, Conditional Statements and Loops." For now, all you need to know is that the if
statement checks to see whether the statement in the parentheses is true or false. If the statement is true, it executes the statements between the curly braces.
A Duration value represents data in terms of time. It is typically used in animation applications, to work with timelines, transitions, keyframes, and so on. As an example, Listing 3-11 demonstrates different ways to represent 3.5 minutes.
Example 3.11. Examples of representing the value 3.5 minutes
var d1 = 3.5m; var d2 = 3m + 30s; var d3 = 3500ms; var d4 = 3m + 0.5s; var d5 = Duration.valueOf(3500);
Listing 3-12 demonstrates Duration's usage in a timeline.
Example 3.12. Using Duration in a timeline
var x: Number = 0; Timeline { at (0s) {x => 0 tween Interpolate.LINEAR}, at (3s) {x => 2.0 tween Interpolate.LINEAR} repeatCount: Timeline.INDEFINITE }
This example changes the x
value from 0 to 2.0 within a timeframe of 3 seconds. To represent indefinite time, we can use Duration.INDEFINITE
.
Timelines are covered in detail in Chapter 13, "Introduction to Animation."
The Duration class provides numerous convenient methods for converting data to and from Duration time. Listing 3-13 shows some examples.
Example 3.13. Converting data to and from Duration values
var d = 4h; var noOfHours = d.toHours(); var noOfMinutes = d.toMinutes(); var noOfSeconds = d.toSeconds(); var noOfMillis = d.toMillis(); var d1 = d.add(10m); // d1 = 250m var d2 = d.sub(1h); // d2 = 3h var d3 = d.mul(10); // d3 = 2400m var d4 = d.div(10); // d4 = 24m
Listing 3-13 demonstrates the build-in functions of the Duration data type. In the third statement, variable d
of Duration data type is converted to minutes using the toMinutes()
function. Likewise, the toSeconds()
and toMillis()
functions are used in the fourth and fifth statements. In addition to the conversion functions, Duration values can be added, subtracted, multiplied and divided using built-in functions as shown in the last four statements.
You will learn more about the Duration data type in Chapter 13.
Type conversion or typecasting refers to changing the value of a variable from one data type into another. This is done to take advantage of certain features of type hierarchies. For instance, values from a more limited set, such as integers, can be stored in a more compact format and later converted to a different format, enabling operations that would not otherwise be possible, such as division with several decimal places of accuracy when there is a need for that.
Casting can be implicit or explicit. Implicit casting are safe and handled by the compiler itself. Normally, upcasting is implicit whereas downcasting requires explicit notation in the code. Listing 3-14 shows an example.
Example 3.14. An example of typecasting
var d: Number = 10.0; var l:Integer = 2; d = l; // This is implicit casting
In this code, casting is implicitly done by the compiler since we are assigning a subtype to a supertype. However, the following code will give a warning:
var d: Number = 10.0; var l:Integer = 2; l = d;
Here is the output:
<src.fx>: warning: possible loss of precision found : Number required: Integer
To avoid this warning, downcasting has to be specified explicitly, using as keyword:
l = d as Integer;
We will discuss casting in more detail when we deal with objects in Chapter 9, "Inheritance."
Sequences in JavaFX Script are similar to arrays in Java, which hold a set of value of similar data type under a single variable name. As shown in Listing 3-15, sequences can be constructed explicitly.
However, they can also be specified as ranges:
[100 .. 200]
Listing 3-16 shows some examples of how sequence variables are declared.
Example 3.16. Some variables of the Sequence type
var nodes : CustomNode[]; var numbers : Number[]; def primes = [2, 3, 5, 7, 11];
Sequences in JavaFX Script are far more powerful and hence will be covered in detail in Chapter 10. This section is just an introduction.
As noted when we discussed data type declarations earlier in the chapter, each data type has its own default value that will be used when no initial value is provided. Table 3-3 summarizes the default values for different data types.
Table 3.3. Default Values for Data Types
Type | Declaration | Default Value | Element Specifier | Literal or Creation Examples |
---|---|---|---|---|
String |
| "" |
|
|
Integer |
| 0 |
|
|
Number |
| 0.0 |
|
|
Boolean |
| false |
|
|
Duration |
| 0ms |
|
|
Other class types |
| null |
|
|
Function types |
| null |
|
|
Sequence types |
| [] |
|
|
In this chapter, you have seen what data types JavaFX offers and how to use them. The primitive data types that are supported by JavaFX are String, Integer, Number, Boolean, and Duration. A String is a set of characters enclosed by either single or double quotes. The Integer data type holds only whole numbers, not fractions or floating point numbers. Integers can be expressed in decimal, octal, or hexadecimal form. A Number can either contain a decimal point, an e (uppercase or lowercase), which is used to represent an exponent in scientific notation, or both. The Boolean data type can hold either true or false. The Duration data type represents values in terms of time such as seconds, milliseconds, and so on.
In the next chapter, you will learn about the operators and expressions available in JavaFX Script.