Dig into some of the new features of Java7 and the scripting language support apis

  • 2020-04-01 01:56:18
  • OfStack

1. The switch conditional statement can be added to the string, the implementation method is to use the string hashcode() value job real value
2. Added a base, binary, that can be used in literals, by prefixing Numbers with "0b" or "0b"
3. Use underscores in literal Numbers to separate Numbers for easy reading without affecting the size. The basic rule is that you can only underline Numbers before and after
4. Java7 makes two changes to exceptions:

4.1. Support for catching multiple exceptions in a catch clause at the same time, and a more precise type of exception when caught and rethrown. Throwable class increase addSuppressed method in Java 7, when an exception is thrown, there may be other abnormal because the exception was inhibited, thus unable to properly throw. Then can move these suppressed by addSuppressed method method, suppressed abnormal will appear in the exception thrown stack information, but can be by getSuppressed method to get these abnormalities. The advantage of doing this is that you don't lose any exceptions, making it easy for developers to test.


public class ReadFile(){
     public void read(String filename) throws IOException {
         FileInputStream input = null;
         IOException readException = null;
         try {
             input = new FileInputStream(filename);
         } catch (IOException ex) {
             readException = ex;
         } finally {
             if (input != null) {
                 try {
                     input.close();
                 } catch (IOException ex) {
                     if (readException != null) {
                         readException.addSuppressed(ex);
                     } else {
                         readException = ex;
                     }
                 }
             }
             if (readException != null) {
                 throw readException;
             }
         }
     }
  } 

This kind of practice is the key to the finally statement of abnormal addSuppressed way to try to produce abnormal.


Java7 has improved the syntax of the catch clause to allow multiple exceptions to be specified in it, separated by "|" between each exception type. It is important to note that the catch exceptions declared in the catch clause cannot have duplicate types, and that one of the exceptions is not allowed to be a subclass of another exception parameter, otherwise a compilation error occurs (small to large). If more than one exception is declared in the catch clause, the specific type of the exception parameter is the minimum upper bound on all of these exception types.

4.2 Using try(request resource){business processing} to automatically free the resource, the resource that can be managed by the try statement needs to meet the condition that its Java class implements the java.lang.autocloseable interface, or a compilation error will occur. The interface's close method is called automatically when resources need to be freed.

5. Method call to optimize variable length parameters:
A new feature introduced in j2se5.0 is the ability to use arguments of variable length in method declarations. The last formal parameter of a method can be specified to represent any number of arguments of the same type. At call time, these parameters are passed as an array. These parameters can also be referenced as arrays in the method body.

6. Java7 introduces a new annotation @safevarargs. This annotation can be used to declare if a developer is confident that a method that USES a variable length parameter will not be used in a similar way with a generic class. The @safevarargs annotation can only be used on methods or constructors with variable parameter length, and methods must be declared static or final, otherwise a compilation error occurs. The premise for a method to use the @safevarargs annotation is that the developer must ensure that the handling of generic type parameters in the method's implementation does not raise type safety issues.

Some scripting languages are supported in the Java virtual machine through the scripting engine. In fact, the script engine manager supports three different ways of finding engines, by name, file extension, and MIME type. Such as


public void greet() throws ScriptException {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        if (engine == null) {
            throw new RuntimeException(" Can't find JavaScript Language execution engine ");
        }
        engine.eval("println('hello');");
    }

It can also be found by getEngingByExtension("js") and getEngineByMimeType("text/javascript"). Once you have an object for the ScriptEngine ScriptEngine, you can execute a piece of code through its eval method and return the result of that code.

7.1 language binding:
A big advantage of the scripting language support API is that it standardizes the way the Java language interacts with the scripting language, enabling programs written in the Java language to conduct two-way method calls and data transfers between scripts. Data transfer is done by language binding objects. A language binding object is simply a hash table that holds and retrieves the data that needs to be Shared. All the data corresponds to an entry in the hash table, which is a simple name-value pair. The interface javax.script.bingings defines the interface to the language binding object, which is inherited from the java.util.map interface. A script engine may bind objects in more than one language during execution. Different languages have different scopes for binding objects. By default, the script engine provides multiple language binding objects to store in the global objects generated during execution, and so on. The ScriptEnging class provides put and get methods to manipulate the default language binding object for specific usage in the script engine. Programs can use this default language binding object directly, or they can use their own language binding object. During script execution, the language binding object can be thought of as an additional variable mapping table. The name in the language binding object is also taken into account when the value of the variable is resolved. Things like global variables that are generated during script execution appear in the language binding object. In this way, two-way data transfer between Java and the scripting language is accomplished.
For example, a string named "name" is added to the ScriptEngine's default language binding object through ScriptEngine's put method, and the object is then referenced directly by name in the script. Similarly, the global variable "message" created in the script can also be retrieved through the get method of ScriptEnging. This enables two-way data transfer between Java programs and scripts. The type conversion in the data transfer process is done by the script engine, and the conversion rules depend on the syntax of the specific language


public void useDefaultBinging() throws ScriptException {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        // ScriptEngine engine = getJavaScriptEnging();
        engine.put("name", "World");
        engine.eval("var message = 'hello,'+name;");
        engine.eval("println(message)");
        Object obj = engine.get("message");
        System.out.println(obj);
    }

In most cases, ScriptEnging's put and get methods are sufficient. The language binding object itself is transparent to the developer if only the put and get methods are used. In some cases, you need to use the program's own language binding object, such as a language binding object that contains data that is unique to the program itself. If you want to use their own language binding object, you can call the script engine creatBingings method or create a javax.mail script. SimpleBingings object, and passed to the script engine's eval method such as:


public void useCustomBinding()throws ScriptException
    {
    ScriptEngine engine = getJavaScriptEngine();
    Bindings bindings = new SimpleBindings();
    bindings.put("hobby","play games");
    engine.eval("println('I like'+hobby);",bindings);
    }

A language-bound object passed through the eval method is only valid in the current eval call and does not change the engine's default language-bound object

7.2 script execution context
Related to the script engine to perform another important interface is javax.mail script. ScriptContext, which contains the script engine in the process of execution context information related to, can be in the servlet specification and JavaEE javax.mail. Servlet. The ServletContext interface to the analogy. The script engine gets information about the execution of the script by invoking the following object, which also allows developers to configure the behavior of the script engine. The upper and lower objects mainly contain the following three types of information.
7.2.1 input and output
We first introduce the configuration information related to the input and output of the script, including the java.io.reader object that the script USES to read the data input during execution, and the java.io.writer object that outputs the correct content and error messages. By default, the input and output of the script occur in the standard console, and if you want to write the output of the script to a file, you can use the following code. Redirect the output of the script to a file using the setWriter method. SetReader and setErrorWriter methods in ScriptContext allow you to set the source of the data input when the script executes and the purpose of the output of the error message when an error is generated, respectively.


public void scriptToFile()throws IOException,ScriptException{
        ScriptEngine engine = getJavaScriptEngine();
        ScriptContext context = engine.getContext();
        context.setWriter(new FileWriter("output.txt"));
        engine.eval("println('hello world!');");
        }

7.2.2 custom properties

There are also methods to get and set attributes in ScriptContext similar to ServletContext, that is, setAttribute and getAttribute. The difference is that attributes in ScriptContext are scoped. Different scopes differ in the order in which they are searched, each of which is represented by a corresponding integer. The smaller the integer value, the more precedence the search order. Properties in a high-priority scope hide properties of the same name in a low-priority scope. Therefore, you need to explicitly specify the scope when setting the property. When you get a property, you can either select the specified scope to look it up, or you can choose to automatically look it up based on the scope priority.
However, the scope included in the script execution context implementation is fixed. Developers are not free to define their own scopes. A list of all available scopes can be obtained from the getScopes method in ScriptContext. There are two predefined scopes in SciptContext: the scope for the constant scriptcontext.engine_scope corresponds to the current script engine, and the scope for the scriptcontext.global_scope corresponds to all script engine objects created from the same engine factory. The former has higher priority. The following cases:


public void scriptContextAttribute(){
        ScriptEngine engine = getJavaScriptEnging();
        ScriptContext context = engine.getContext();
        context.setAttribute("name","World",ScriptContext.GLOBAL_SCOPE);
        context.setAttribute("name","Bob",ScriptContext.ENGINE_SCOPE);
        context.getAttribute("name");//A value of Bob
        }

7.2.3 language binding objects

The last type of information in the script execution context is the language binding object. Language binding objects are also scoped. The same scope priority order applies to language binding objects. This priority order affects the resolution of variables during script execution. The following cases:


public void scriptContextBindings()throws ScriptException
    {
    ScriptEngine engine = getJavaScriptEnging();
    ScriptContext context = engine.getContext();
    Bindings bindings1 = engine.createBindings();
    bindings1.put("name","World");
    context.setBindings(bindings1,ScriptContext.GLOBAL_SCOPE);
    Bindings bindings2 = engine.createBindings();
    bindings2.put("name","Bob");
    context.setBindings(bindings2,ScriptContext.ENGINE_SCOPE);
    engine.eval("println(name);");//The results for Bob
    }

Also can be Bindings Bindings = context. GetBindings (scriptcontext.engine_scope);

Bindings. Put (" name ", "World")
Engine. Eval (" println (name);" );

7.3 compilation of script:
Scripting languages are generally interpreted and executed. The script engine needs to parse the script before executing it at run time. In general, scripts run slower by interpreting the execution than they do after compilation. When a script needs to be executed many times, the script can be compiled first. The compiled scripts do not need to be parsed repeatedly to improve execution efficiency. Not all script engines support compiling scripts. If the scripting engine supports this feature, it implements the javax.script.Compilable interface to declare it. Users of script engines can take advantage of this ability to increase the efficiency of scripts that require multiple executions. The JavaScript scripting engine that comes with Java SE supports compiling scripts.
The following code, Compilable interface of the compile method is used to compile the script code, compile results by javax.script.Com piledScript said. Since not all scripting engines support the Compilable interface, you need to use instanceof to judge. In the run method, the script is executed using the CompiledScript's eval method. A script is executed 100 times in the code to demonstrate the performance advantage of a compiled script when executed repeatedly.


public CompiledScript compile(String scriptText) throws ScriptException {
        ScriptEngine engine = getJavaScriptEngine();
        if (engine instanceof Compilable) {
            CompiledScript script = ((Compilable) engine).compile(scriptText);
        }
        return null;
    }
    public void run(String scriptText) throws ScriptException {
        CompiledScript script = compile(scriptText);
        if (script == null) {
            return;
        }
        for (int i = 0; i < 100; i++) {
            script.eval();
        }
    }

The CompiledScript eval method takes the same arguments as the ScriptEngine eval method.

7.4 method invocation in the script
In scripts, the most common and practical is the method. Some script engines allow the user to invoke a method in a script separately. Scripting engines that support this method invocation approach can implement the javax.script.invocable interface. The Invocable interface allows you to invoke top-level methods in scripts, as well as member methods in objects. If the top-level method in the script or the member method in the object implements the interface in Java, the implementation object of the corresponding Java interface in the script can be obtained through the method in the Invocable interface. This allows you to define interfaces in the Java language and implement them in scripts. The rest of the code in the program that USES this interface does not know that the interface is implemented by scripts. Like the Compilable interface, ScriptEngine is optional for implementation of the Invocable interface.
The following code calls the top-level method in the script through the Invocable interface's invokeFunction, and the arguments are passed to the method in the script. Because the JavaScript scripting engine that comes with JavaSE implements the Invocable interface, the decision on whether the engine implements the Invocalbe interface is omitted
An example of calling a script top-level method in Java:


public void invokeFunction()throws ScriptException,NoSuchMethodException{
        ScriptEngine engine = getJavaScriptEngine();
        String scriptText ="function greet(name) { println ( 'hello,'+name  ) ;}";
        engine.eval(scriptText);
        Invocable invocable=(Invocable)engine;
        invocable.invokeFunction("greet","World");
        }

If the called method is a member of the object in the script, you need to use the invokeMethod method. As shown in the code below, the getGreeting method belongs to the object obj and needs to be passed in as an argument when invoked.

// an example of calling a member method of a script object in Java


public void inokeMethod()throws ScriptException,NoSuchMethodException
    {
    ScriptEngine engine = getJavaScriptEngine();
    String scriptText = "var obj={ getGreeting:function(name){return 'Hello,'+name;}};";
    engine.eval(scriptText);
    Invocable invocable = (Invocable)engine;
    Object scope = engine.get("obj");
    Object result = invocable.invokeMethod(scope,"getGreeting","Alxx");
    System.out.println(result);
    }

The method invokeMethod is similar to the method invokeFunction, except that invokeMethod specifies the object that contains the method to be invoked.

 

Implement the Java interface in the 7.5 script

In some scripting engines, you can define the interface in the Java language and write the implementation of the interface in the script, so that the rest of the program can only interact with the Java interface and not care how the interface is implemented. Greet is a java-defined interface in the following code, which contains a getGreeting method. To implement this interface in a script, you can get the object of the interface implemented by the script through the getInterface method and call the method in it.


public void useInterface() throws ScriptException {
        ScriptEngine engine = getJavaScriptEngine();
        String scriptText = "function getGreeting(name){return 'Hello,'+name;}";
        engine.eval(scriptText);
        Invocable invocable = (Invocable) engine;
        Greet greet = invocable.getInterface(Greet.class);
        System.out.println(greet.getGreeting("World"));
    }

The implementation of the interface above is done by the top-level method in the script. Likewise, it can be implemented by the member methods of the objects in the script. In this case, another overloaded form of the getInterface method can accept an extra parameter to specify the object on which the interface implementation resides.

Because of its simple and flexible syntax, scripting languages are very suitable for users with little or no programming background. These users can customize the business logic and user interface of the program through scripting languages, which can achieve a good balance between the ease of use and the flexibility of the program. The scripting language Lua, for example, is widely used in game development to customize the game's internal behavior and user interface.

8. While the reflection API provides flexibility to Java programs, it also imposes additional performance costs. Due to the implementation mechanism of the reflection API, the dynamic implementation of the reflection API for the same operation, such as calling a method, is about an order or two of magnitude slower than the method written directly in the source code. With the improved implementation of the Java virtual machine, the performance of the reflection API has improved significantly. However, this performance gap exists, so in some applications where performance requirements are high, reflection apis should be used with caution.


Related articles: