} } }

    Java7 一些新特点及脚本说话支撑API--笔记

    添加时间:2013-5-5 点击量:

    1.switch前提语句中可以参加字符串了,实现办法是哄骗了字符串的hashcode()值功课真正的值
    2.增长了一种可以在字面量中应用的进制,二进制,经由过程在数字前面加“0b”或“0B”
    3.在数字字面量中应用下划线来分隔数字便利浏览,不影响数值大小。基起原根蒂根基则是前后都是数字的才可以呈现下划线
    4.java7对异常做了两个批改:


      4.1.支撑在一个catch子句中同时捕获多个异常,别的一个是在捕获并从头抛出异常时的异常类型加倍正确。java7中Throwable类增长addSuppressed办法,当一个异常被抛出的时辰,可能有其他异常因为该异常而被按捺住,从而无常抛出。这时可以经由过程addSuppressed办法把这些被按捺的办法记录下来,被按捺的异常会呈如今抛出的异常的客栈信息中,也可以经由过程getSuppressed办法来获取这些异常。如许做的益处是不会丧失任何异常,便利开辟人员测试。




     1 public class ReadFile(){
    
    2 public void read(String filename) throws IOException {
    3 FileInputStream input = null;
    4 IOException readException = null;
    5 try {
    6 input = new FileInputStream(filename);
    7 } catch (IOException ex) {
    8 readException = ex;
    9 } finally {
    10 if (input != null) {
    11 try {
    12 input.close();
    13 } catch (IOException ex) {
    14 if (readException != null) {
    15 readException.addSuppressed(ex);
    16 } else {
    17 readException = ex;
    18 }
    19 }
    20 }
    21 if (readException != null) {
    22 throw readException;
    23 }
    24 }
    25 }
    26


    这种做法的关键在于把finally语句中产生的异常经由过程addSuppressed办法加到try语句产生的异常中。



    java7改进了catch子句的语法,容许在此中指定多种异常,每个异常类型之间应用“|”来分隔。须要重视的是在catch子句中声明捕获的这些异常,不克不及呈现反复的类型,也不容许此中的某个异常是别的一个异常参数的子类,不然会呈现编译错误(从小到大写就没题目)。若是在catch子句中声了然多个异常,那么异常参数的具体类型是所有这些异常类型的最小上界。


      4.2应用try(申请资料){营业处理惩罚}来主动开释资料,可以或许被try语句所经管的资料须要满足一个前提,那就是其java类要实现java.lang.AutoCloseable接口,不然会呈现编译错误。当须要开释资料的时辰该接口的close办被主动调用。


    5. 优化变长参数的办法调用:
    j2se5.0中引入的一个新特点就是容许在办法声明中应用可变长度的参数。一个办法的最后一个情势参数可以被指定为代表随便率性多个雷同类型的参数。在调用的时辰,这些参数是以数组的情势来传递的。在办法体中也可以遵守数组的体式格式来引用这些参数。


    6. java7引入了一个新的注解@SafeVarargs.若是开辟人员确信某个应用了可变长度参数的办法,在与泛型类一路应用进不会呈现类似的景象,就可以用这个注解进行声明。@SafeVarargs注解只能用在参数长度可变的办法或机关办法上,且办法必须声明为static或final,不然会呈现编译错误。一个办法应用@SafeVarargs注解的前提是,开辟人员必须确保这个办法的实现中对泛型类型参数的处理惩罚不会激发类型安然题目。


    7.java中在java虚拟机中支撑一些脚本说话是经由过程脚本引擎。实际上脚本引擎经管器共支撑三种查找引擎体式格式,分别经由过程名称,文件扩大名和MIME类型来完成。如



    public void greet() throws ScriptException {
    
    ScriptEngineManager manager
    = new ScriptEngineManager();
    ScriptEngine engine
    = manager.getEngineByName(JavaScript);
    if (engine == null) {
    throw new RuntimeException(找不到JavaScript说话履行引擎);
    }
    engine.eval(
    println(hello););
    }


    还可以经由过程getEngingByExtension(js)和getEngineByMimeType(text/javascript)来查找到。获得脚本引擎ScriptEngine的对象后,经由过程其eval办法可以履行一段代码,并返回这段代码的履行成果。


    7.1 说话绑定:
    脚本说话支撑api的一个很大上风在于它规范了java说话与脚本说话之间的交互体式格式,使java说话编写的法度可以与脚本之间进行双向的办法调用和数据传递。数据传递是经由过程说话绑定对象来完成的。所谓的说话绑定对象就是一个简单的哈希表,用来存放和获取须要共享的数据。所稀有据都对应这个哈希表中的一个条目,是简单的名值对。接口javax.script.Bingings定义了说话绑定对象的接口,它持续自java.util.Map接口。一个脚本引擎在履行过程中可能会应用多个说话绑定对象。不合说话绑定对象的感化域不合。在默认景象下,脚本引擎会供给多个说话绑定对象,用来存放在履行过程中产生的全局对象等。ScriptEnging类供给了put和get办法对脚本引擎定应用哉的默认说话绑定对象进行操纵。法度可以直接应用这个默认的说话绑定对象,也可以应用本身的说话绑定对象。在脚本履行过程中,可以将说话绑定对象算作是一个额外的变量映射表。在解析变量值的时辰,说话绑定对象中的名称也会被推敲在内。脚本 履行过程中产生的全局变量等内容,会呈如今说话绑定对象中。经由过程这种体式格式,就完成了Java与脚本说话之间的双向数据传递。
    如经由过程ScriptEngine的put办法向脚本引擎默认的说话绑定对象中添加了一个名为“name”的字符串,接着在脚本中直接按照名称来引用这个对象。同样,在脚本中创建的全局变量“message”也可以经由过程ScriptEnging的get办法来获取。如许就实现了Java法度与脚本之间的双向数据传递。数据传递过程中的类型转换是由脚本引擎来完成的,转换规矩取决于具体的说话的语法



    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);
    }


    在大多半景象下,应用ScriptEnging的put和get办法就足够了。若是仅应用put和get办法,说话绑定对象本身对于开辟人员来说是透明的。在某些景象下,须要应用法度本身的说话绑定对象,比如说话绑定对象中包含了法度本身独有的数据。若是应用本身的说话绑定对象,可以调用脚本引擎的creatBingings办法或创建一个javax.script.SimpleBingings对象,并传递给脚本引擎的eval办法如:



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


    经由过程eval办法传递的说话绑定对象,仅在当前eval调用中生效,并不会改变引擎默认的说话绑定对象


    7.2 脚本履行高低文
    与脚本引擎履行相干的别的一个首要接口是javax.script.ScriptContext,此中包含脚本引擎履行过程中的相干高低文信息,可以与JavaEE中servlet规范中的javax.servlet.ServletContext接口来进行类比。脚本引擎经由过程引高低文对象来获取与脚本履行相干的信息,也容许开辟人员经由过程此对象来设备脚本引擎的行动。该高低对象中首要包含以下3类信息。
    7.2.1 输入与输出
    起首介绍与脚本输入和输出相干的设备信息,此中包含脚本在履行顶用来读取数据输入的java.io.Reader对象以及输出正确内容和失足信息的java.io.Writer对象。在默认景象下,脚本的输入输出都产生在标准把握台中,若是把脚本的输出写入到文件 中,可以应用如下代码。经由过程setWriter办法把脚本的输出重定向到一个文件 中。经由过程ScriptContext的setReader和setErrorWriter办法可以分别设置脚本履行时的数据输入起原和产生错误时失足信息的输出 目标。



    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 自定义属性


    ScriptContext中也有与ServletContext中类似的获取和设置属性的办法,即setAttribute和getAttribute.所不合的是,ScriptContext中的属性是有感化域之分的。不合感化域的差别在于查找时的次序不合,每个感化域都以一个对应的整数默示其查找次序。该整数值越小,申明查找时的次序越优先。优先级高的感化域中的属性会隐蔽优先级低中的同名属性。是以,设置属性时须要显式指定地点的感化域。在获取属性的时辰,即可选择指定的感化域中查找,也可以选择按照感化域优先级主动进行查找。
    不过脚本履行高低文实现 中包含的感化域是固定的。开辟人员不克不及随便定义本身的感化域。经由过程ScriptContext的getScopes办法可以获得所有可用的感化域列表。SciptContext中预先定义了两个感化域:常量ScriptContext.ENGINE_SCOPE默示的感化域对应的是当前的脚本引擎,而ScriptContext.GLOBAL_SCOPE默示的感化域对应的是从同一引擎工厂中创建出来的所有脚本引擎对象。前者的优先级较高。如下例:



    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);//值为Bob
    }


    7.2.3 说话绑定对象


    脚本履行高低文中的最后一类信息是说话绑定对象。说话绑定对象也是与感化域相对应的。同样的感化域优先级次序对说话绑定对象也实用。如许的优先级次序会对脚本履行时的变量解析产生影响。如下例:



    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););//成果为Bob
    }


    还可以Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);


    bindings.put(name,World)
    engine.eval(println(name););


    7.3 脚本的编译:
    脚本说话一般是申明履行的。脚本引擎在运行时须要先解析脚本之后再履行。一般来说,经由过程申明履行的体式格式运行脚本的速度比编译之后再运行会慢一些。当一段脚本须要被多次反复履行时,可以先对脚本进行编译。编译之后的脚本履行时不须要反复解析,可以进步履行效力。不是所有脚本引擎都支撑对脚本进行编译。若是脚本引擎支撑这一特点,它会实现javax.script.Compilable接口来声明这一点。脚本引擎的应用者可以哄骗这个才能来进步须要多次履行的脚本的运行效力。Java SE中自带的JavaScript脚本引擎是支撑对脚本进行编译的。
    如下代码中,Compilable接口的compile办法用来对脚本代码进行编译,编译的成果用javax.script.CompiledScript来默示。因为不是所有的脚本引擎都支撑Compilable接口,是以这里须要用instanceof进行断定。在run办法中,经由过程CompiledScript的eval办法就可以履行脚本。代码中把一段脚本反复履行了100次,以此申明编译完的脚本在反复履行时的机能上风。



    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;
    }
    forint i = 0; i < 100; i++) {
    script.eval();
    }
    }


    CompiledScript的eval办法所接管的参数与ScriptEngine的eval办法是雷同的。


    7.4 脚本中办法调用
    在脚本中,最常见的和实用的就是办法。有些脚本引擎容许应用者零丁调用脚本中某个办法。支撑这种办法调用体式格式的脚本引擎可以实现javax.script.Invocable接口。经由过程Invocable接口可以调用脚本中的顶层办法,也可以调用对象中的成员办法。若是脚本中顶层办法或对象中的成员办法实现了Java中的接口,可以经由过程Invocable接口中的办法来获取脚本中响应的Java接口的实现对象。如许就可以在Java说话中定义接口,在脚本中实现接口。法度中应用该接口的其他项目组代码并不知道接口是由脚底本实现的。与Compilable接口一样,ScriptEngine对于Invocable接口的实现也是可选的。
    下面代码经由过程Invocable接口的invokeFunction来调用脚本中的顶层办法,调用时的参数会被传递给脚本中的办法。因为JavaSE自带的JavaScript脚本引擎实现了Invocable接口,所以这里省去了对引擎是否实现了Invocalbe接口的断定
                    在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);
    }


    若是被调用办法是脚本中对象的成员办法,就须要应用invokeMethod办法,如下面代码中所示,代码中getGreeting办法是属于对象obj的,在调用的时辰须要把这个对象作为参数传递进去。


              //在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);
    }


    办法invokeMethod与办法invokeFunction用法差不久不多,差别在于invokeMethod要指定包含待调用办法的对象。



    7.5 脚本中实现java接口


    在有些脚本引擎中,可以在Java说话中定义接口,并在脚本中编写接口的实现,如许法度中的其他项目组可以只同Java接互,并不须要关怀接口是由什么体式格式来实现的。鄙人面代码中Greet是用Java定义的接口,此中包含一个getGreeting办法。在脚本中实现这个接口,经由过程getInterface办法可以获得由脚本实现的这个接口的对象,并调用此中的办法。



    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));
    }


    上方中的接口的实现是由脚本中的顶层办法来完成的。同样的,也可以由脚本中对象的成员办法来实现。对于这种景象,getInterface办法别的一种重载情势可以接管一个额外的参数来指定接话柄现地点的对象。


    因为脚本说话的语法简单和灵活,很是实用于没有或只有少量编程靠山的用户来应用,这些用户可以经由过程脚本说话来定制法度的营业逻辑和用户界面等,经由过程脚本说话可以在法度的易用性和灵活性之间达到一个斗劲好的均衡。比如脚本说话Lua就被广泛应用在游戏开辟中,用来对游戏的内部行动和用户界面进行定制。


    8. 反射API在为Java法度带来灵活性的同时,也产生了额外的机能价格,因为反射API的实现机制,对于雷同的操纵,比如调用一个办法,用反射API来动态实现比直接在源代码中编写的体式格式可能慢一到两个数量级。跟着Java虚拟机实现的改进,反射API的机能已经有了很是大的提拔。然则这种机能的差距是客观存在的,是以,在某些对机能请求斗劲高的应用中,要慎用反射API。

    容易发怒的意思就是: 别人做了蠢事, 然后我们代替他们, 表现出笨蛋的样子。—— 蔡康永
    分享到: