动态语言支持

本文是我们名为“ 高级Java ”的学院课程的一部分。

本课程旨在帮助您最有效地使用Java。 它讨论了高级主题,包括对象创建,并发,序列化,反射等。 它将指导您完成Java掌握的过程! 在这里查看

1.简介

在本教程的这一部分中,我们的注意力将完全集中在Java中的脚本和动态语言支持上。 从Java 7开始,JVM就直接支持现代动态语言(也通常称为脚本语言),并且Java 8版本对该空间进行了进一步的增强。

动态语言的优势之一是程序的行为是在运行时定义的,而不是在编译时定义的。 在这些语言中, Rubyhttps://www.ruby-lang.org/en/ ), Pythonhttps://www.python.org/ )和JavaScripthttp://en.wikipedia.org/wiki/ JavaScript )已广受欢迎,并且是目前使用最广泛的JavaScript 。 我们将研究Java脚本API如何为将这些语言集成到现有Java应用程序中提供一种方法。

2.动态语言支持

众所周知,Java是一种静态类型的语言。 这意味着在编译时可获得类的所有类型化信息,其成员,方法参数和返回值。 使用所有这些详细信息,Java编译器会发出强类型的字节码,然后可以在运行时由JVM有效解释。

但是,动态语言在运行时而不是编译时执行类型检查。 处理动态语言的挑战是如何实现一个运行时系统,该系统可以选择一种最合适的方法实现,以在程序编译后进行调用。

长期以来,JVM一直没有对动态类型语言的特殊支持。 但是Java 7版本引入了新的invokedynamic指令,该指令使运行时系统(JVM)可以自定义调用站点(调用方法的位置)与方法实现之间的链接。 它确实为在JVM平台上提供有效的动态语言支持和实施打开了一扇门。

3.脚本API

作为2006年发行的Java 6的一部分,新的脚本API已在javax.script包下引入。 该可扩展API旨在插入大多数脚本语言(提供脚本引擎实现)并在JVM平台上运行。

实际上,Java脚本API非常小而且非常简单。 开始使用脚本API的第一步是创建ScriptEngineManager类的新实例。 ScriptEngineManager提供了从正在运行的应用程序类路径中按名称搜索和检索可用脚本引擎的功能。

每个脚本引擎使用各自的ScriptEngine实现表示,并且实质上提供了使用eval()函数家族(具有多个重载版本)执行脚本的能力。 已经有许多流行的脚本(动态)语言提供了对Java脚本API的支持,在本教程的下一部分中,我们将通过玩JavaScriptGroovyRuby / JRubyPython / Jython来了解该API在实践中的效果。 。

4. JVM上JavaScript

我们并非偶然地开始使用JavaScript语言,因为它是Java标准库脚本API支持的最早的脚本语言之一。 而且,从总体上讲,它是每个Web浏览器都能理解的单一编程语言。

eval()函数以最简单的形式执行脚本,并以纯Java字符串的形式传递给脚本。 该脚本没有与评估者(或调用者)共享的状态,并且是独立的代码段。 但是,在典型的实际应用程序中,这种情况非常罕见,并且经常需要将一些变量或属性提供给脚本才能执行一些有意义的计算或操作。 话虽如此,让我们看一个使用简单变量绑定评估真实JavaScript函数调用的简单示例:

final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName( "JavaScript" );
        
final Bindings bindings = engine.createBindings();
bindings.put( "str", "Calling JavaScript" );
bindings.put( "engine", engine );
        
engine.eval( "print(str + ' from ' + engine.getClass().getSimpleName() )", bindings );

执行后,将在控制台上打印以下输出:

Calling JavaScript from RhinoScriptEngine

相当长一段时间以来Rhino一直是JVM上可用的单个JavaScript脚本引擎。 但是Java 8版本带来了一个名为NashornJavaScript脚本引擎的全新实现( http://www.oracle.com/technetwork/articles/java/jf14-nashorn-2126515.html )。

从API的角度来看,并没有太多的区别,但是内部实现却有很大的不同,从而保证了更好的性能。 这是使用Nashorn JavaScript引擎重写的同一示例:

final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName( "Nashorn" );
        
final Bindings bindings = engine.createBindings();
bindings.put( "engine", engine );
        
engine.eval( "print(str + ' from ' + engine.getClass().getSimpleName() )", bindings );

以下输出将打印在控制台上(请注意这次不同的脚本引擎实现):

Calling JavaScript from NashornScriptEngine

尽管如此,我们看过JavaScript代码片段的例子却是微不足道的。 实际上,您可以使用重载的eval()函数调用来评估整个JavaScript文件,并仅在JavaScript中实现相当复杂的算法。 在接下来的部分中,我们将在探索其他脚本语言时看到这些示例。

5.在JVM上使用Groovy

Groovyhttp://groovy.codehaus.org )是JVM平台最成功的动态语言之一。 它通常与Java并行使用,但是它也提供Java脚本API引擎实现,并且可以与JavaScript相似的方式使用。

让我们通过开发一个小的独立脚本,使这个Groovy示例更加有意义和有趣,该脚本在控制台上打印出通过调用Java应用程序与其共享的藏书中每本书的一些详细信息。

Book类非常简单,只有两个属性,author和title:

public class Book {
    private final String author;
    private final String title;
    
    public Book(final String author, final String title) {
        this.author = author;
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public String getTitle() {
        return title;
    }
}

Groovy脚本(仅命名为script.groovy )使用一些漂亮的语言功能(例如闭包和字符串插值)将书籍属性输出到控制台:

books.each { 
    println "Book '$it.title' is written by $it.author"
}

println "Executed by ${engine.getClass().simpleName}"
println "Free memory (bytes): " + Runtime.getRuntime().freeMemory()

现在,让我们使用Java脚本API和预定义的书籍集合(当然,有关Groovy的所有内容)执行这个Groovy脚本:

final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName( "Groovy" );
	    
final Collection< Book > books = Arrays.asList(
	new Book( "Venkat Subramaniam", "Programming Groovy 2" ),
	new Book( "Ken Kousen", "Making Java Groovy" )
    );
	            
final Bindings bindings = engine.createBindings();
bindings.put( "books", books );
bindings.put( "engine", engine );
        
try( final Reader reader = new InputStreamReader( 
        Book.class.getResourceAsStream("/script.groovy" ) ) ) {
    engine.eval( reader, bindings );        
}

请注意, Groovy脚本引擎具有对Java标准库的完全访问权限,并且不需要任何附加绑定。 为了确认这一点,上述Groovy脚本的最后一行通过调用Runtime.getRuntime()静态方法访问当前的运行时环境,并打印出可用于运行JVM的可用堆数量(以字节为单位)。 以下示例输出将出现在控制台上:

Book 'Programming Groovy 2' is written by Venkat Subramaniam
Book 'Making Java Groovy' is written by Ken Kousen
Executed by GroovyScriptEngineImpl
Free memory (bytes): 153427528

Groovy推出至今已有10年了。 由于其创新的语言功能(类似于Java语法)以及与现有Java代码的出色互操作性,它很快变得非常流行。 看起来lambda和Java 8中的Stream API的引入使Groovy的选择不太吸引人,但是Java开发人员仍然广泛使用它。

6. JVM上的Ruby

几年前, Rubyhttps://www.ruby-lang.org/en/ )是用于Web应用程序开发的最流行的动态语言。 尽管如今它的流行程度已逐渐消失,但Ruby及其生态系统在现代Web应用程序开发中带来了许多创新,激发了许多其他编程语言和框架的创建和发展。

JRubyhttp://jruby.org/ )是JVM平台的Ruby编程语言的实现。 与Groovy相似,它还提供了与现有Java代码的出色互操作性,从而保留了Ruby语言语法的美感。

让我们用Ruby语言(名为script.jruby )从JVM上Groovy脚本部分重写Groovy脚本,并使用Java脚本API对其进行评估。

$books.each do |it| 
    java.lang.System.out.println( "Book '" + it.title + "' is written by " + it.author )
end

java.lang.System.out.println( "Executed by " + $engine.getClass().simpleName )
java.lang.System.out.println( "Free memory (bytes): " +   
        java.lang.Runtime.getRuntime().freeMemory().to_s )

脚本评估代码几乎保持不变,只是脚本引擎和示例图书合集不同,而这些全都与Ruby有关。

final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName( "jruby" );
	    
final Collection< Book > books = Arrays.asList(
	new Book( "Sandi Metz", "Practical Object-Oriented Design in Ruby" ),
	new Book( "Paolo Perrotta", "Metaprogramming Ruby 2" )
    );
	            
final Bindings bindings = engine.createBindings();
bindings.put( "books", books );
bindings.put( "engine", engine );
        
try( final Reader reader = new InputStreamReader( 
        Book.class.getResourceAsStream("/script.jruby" ) ) ) {
    engine.eval( reader, bindings );        
}

以下示例输出将出现在控制台上:

Book 'Practical Object-Oriented Design in Ruby' is written by Sandi Metz
Book 'Metaprogramming Ruby 2' is written by Paolo Perrotta
Executed by JRubyEngine
Free memory (bytes): 142717584

从上面的JRuby代码片段可以看出,使用标准Java库中的类有点冗长,并且必须以程序包名称作为前缀(有一些技巧可以避免这种情况,但是我们不做这些特定的细节)。

7. JVM上的Python

我们最后一个但并非最不重要的示例将展示JVM平台上的Pythonhttps://www.python.org/ )语言实现,称为Jythonhttp://www.jython.org/ )。

Python语言最近获得了广泛的关注,并且其流行程度每天都在增长。 它被科学界广泛使用,并具有从网络开发到自然语言处理的大量库和框架。

遵循与Ruby相同的路径,我们将使用Python语言(名称为script.py )从JVM部分的Groovy重写示例脚本,并使用Java脚本API对其进行评估。

from java.lang import Runtime

for it in books: 
    print "Book '%s' is written by %s" % (it.title, it.author)

print "Executed by " + engine.getClass().simpleName
print "Free memory (bytes): " + str( Runtime.getRuntime().freeMemory() )

让我们实例化Jython脚本引擎,并使用已经熟悉的Java脚本API执行上面的Python脚本。

final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName( "jython" );
	    
final Collection< Book > books = Arrays.asList(
        new Book( "Mark Lutz", "Learning Python" ),
        new Book( "Jamie Chan", "Learn Python in One Day and Learn It Well" )
    );
	            
final Bindings bindings = engine.createBindings();
bindings.put( "books", books );
bindings.put( "engine", engine );
        
try( final Reader reader = new InputStreamReader( 
        Book.class.getResourceAsStream("/script.py" ) ) ) {
    engine.eval( reader, bindings );        
}

以下示例输出将在控制台上打印出来:

Book 'Learning Python' is written by Mark Lutz
Book 'Learn Python in One Day and Learn It Well' is written by Jamie Chan
Executed by PyScriptEngine
Free memory (bytes): 132743352

Python作为编程语言的强大之处在于其简单性和陡峭的学习曲线。 随着一群Python开发人员的加入,以某种可扩展性机制将Python脚本语言集成到Java应用程序中的能力听起来像是一个有趣的主意。

8.使用脚本API

Java 脚本API是通过可扩展的脚本支持来丰富Java应用程序的好方法,只需选择您的语言即可。 这也是插入域专用语言 (DSL)的最简单方法,并允许业务专家以最方便的方式表达其意图。

JVM本身的最新更改(请参见“ 动态语言支持”部分)使它成为适用于不同动态(脚本)语言实现的更友好的运行时平台。 毫无疑问,将来会有越来越多的脚本语言引擎可用,这为与新的和现有的Java应用程序无缝集成打开了大门。

9.接下来

从这部分开始,我们实际上是在开始有关Ja​​va作为语言和JVM作为高级运行时执行平台的高级概念的讨论。 在本教程的下一部分中,我们将研究Java Compiler API和Java Compiler Tree API,以学习如何在运行时操作Java源代码。

9.下载代码

这是动态语言支持课程,是高级Java课程的第12部分。 您可以在此处下载源代码: advanced-java-part-12

翻译自: https://www.javacodegeeks.com/2015/09/dynamic-languages-support.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值