第一章  入门

第一节 简介

Xtend是一种静态类型的编程语言,可以转化为可理解的Java源代码。其语法和语义构成基于Java编程语言,但在许多方面得到改进:

扩展方法 - 增强封闭类型新功能

Lambda表达式 - 简洁的匿名函数常量语法

ActiveAnnotations (积极的注解)- 注解处理的增强因子

运算符重载 - 使您的库更具表现力

强大的开关表达式 - 隐式的类型转换

多重调度 - 又名:多态方法调用

模板表达式 - 具有智能空白处理

没有语句 - 一切都是表达

属性 - 简化了getter和setter的访问

类型推断 - 可以少写类型签名

完全支持Java泛型 - 包括所有一致性和转换规则

翻译为Java而不是字节码 - 了解发生了什么,并可将代码用于Android或GWT等平台

与其他JVM语言不同,Xtend 与Java 具有零互操作性问题:您编写的所有内容都与预期的Java代码完全一致。与此同时,Xtend更加简洁、可读和表现力。Xtend的小型库只是一个薄层,提供有用的实用工具和在顶层提供Java开发工具包(JDK)的扩展。

当然,也可以通过Java来完全透明地调用Xtend方法。此外,Xtend还提供现代风格的、基于Eclipse的IDE,并与Eclipse Java开发工具(JDT)紧密集成,包括调用层次结构、重命名重构、调试等功能。

第二节  Hello,World

就像你看到看到其他任何语言一样,第一件事是Hello World的例子。在Xtend中,它代码为:

class HelloWorld {

def static void main(String[] args) {

println("Hello World")

}

}

Xtend看起来和Java非常相似。乍一看,主要区别似乎是def关键字来声明一个方法。同样在Java中,必须将类和main方法定义为应用程序的入口点。诚然,Hello World程序没有体现出Xtend的优势。可当你让程序真正的做一些事情时,真正的表现力将会释放出来,这将会在下一秒学到。

Xtend类驻留在普通的Eclipse Java项目中。一旦安装了SDK,Eclipse将自动将所有类转换为Java源代码。默认情况下,您将在源代码文件夹xtend-gen中找到它。hello world示例被转换为以下Java代码:

// Generated Java Source Code

import org.eclipse.xtext.xbase.lib.InputOutput;

public class HelloWorld {

public static void main(final String[] args) {

InputOutput.<String>println("Hello World");

}

}

生成的Java代码中唯一令人惊讶的可能是引用库的InputOutput类。它是运行时库(runtime library )的一部分,一个很好的工具,可以非常方便地在表达式中使用。

您可以将Xtend类放入任何Eclipse或Maven的Java项目源文件夹中。如果项目尚未正确配置,Eclipse会告诉你丢失的库。xtend.lib必须在类的路径上。IDE将提供一个快速修复来添加它。

下一件事是,在工作区(workSpace)中,实现一个示例项目。在在Eclipse导航(Navigator)视图任意位置单击鼠标右键,并选择New(新建)→Example(示例)...。

在出现的对话框中,您将找到Xtend的两个示例:

Xtend介绍示例(Xtend Introductory Examples),包含几个示例代码片段,说明Xtend的某些方面优势。例如,它显示了如何允许编写如下代码构建API:

assertEquals(42.km/h, (40_000.m + 2.km) / 60.min)

下一节中详细介绍的电影示例也包括在那里。

Xtend的Euler解决方案(Xtend Solutions For Euler),您可以在Project Euler中找到一些问题的解决方案。这些例子利用了Xtend的整体表现力。例如Euler问题1可以用这个表达式来解决:

(1..999).filter[ i | i % 3 == 0 || i % 5 == 0 ].reduce[ i1, i2 | i1 + i2 ]

第三节 电影示例

电影示例包含在示例项目Xtend Introductory Examples(src / examples6 / Movies.xtend)中,是读取关于电影的数据文件,并对其进行一些分析。

数据

电影数据库是纯文本文件(data.csv),具体描述电影的数据集。以下是一个示例数据集:

Naked Lunch  1991  6.9  16578  Biography  Comedy  Drama  Fantasy

值由两个空格分隔。列是:

1.标题(title)

2.年份(year)

3.评级(rating)

4.票数(numberOfVotes)

5.类别(categories)

让我们定义一个表示数据集的数据类Movie:

@Data class Movie {

String title

int year

double rating

long numberOfVotes

Set<String> categories

}

电影类是POJO,数据集中的每列都有强类型字段。@Data注解将会把类变成一个不变值类,那么它会得到:

l 每个字段的getter方法,

l 一个hashCode()/ equals()实现,

l Object.toString()实现,

l 构造函数按所有字段的声明顺序接受值。

解析数据

现在让我们在同一个文件中添加另一个类,并一个名为movies的字段,初始化为列表。我们解析文本文件并将数据记录转换为Movie类:

import java.io.FileReader

import java.util.Set

import static extension com.google.common.io.CharStreams.*

class Movies {

val movies = new FileReader('data.csv').readLines.map [ line |

val segments = line.split('  ').iterator

 return new Movie(

segments.next,

Integer.parseInt(segments.next),

Double.parseDouble(segments.next),

Long.parseLong(segments.next),

segments.toSet

)

]

}

字段的类型可以从右侧的表达式来推断。这被称为局部类型推断,在Xtend中随处可见。我们希望该字段是final,所以我们使用关键字val,将其声明为一个值变量(只读变量)。

右侧的初始化,首先创建一个新的FileReader。然后在该实例中调用方法readLines()。但是如果你看看FileReader,你不会找到这个方法。事实上,readLines()是来自Google Guava的CharStreams的静态方法,它被导入作为扩展( extension)。扩展允许我们使用这种可读的语法。

import static extension com.google.common.io.CharStreams.*

CharStreams.readLines(Reader)使用另一个扩展方法map返回List<String>类型,其在运行时库中定义的(ListExtensions.map(...)),并自动导入,因此可用于所有列表。该map扩展需要一个函数作为参数。它基本上为列表中的每个值调用该函数,并返回另一个包含函数调用结果的列表。实际上,这个映射是懒惰地执行的,如果你不访问列表的结果值,那么映射函数就永远不会被执行。

而函数对象是使用lambda表达式(方括号中的代码)创建的。在lambda中,我们处理文本文件中的一行,并通过使用两个空格字符作为分隔符作为分割符,将其转换为movie。对于拆分操作的结果,调用iterator()方法。您可能知道String.split(String)返回一个字符串数组(String[]),当我们调用Iterable.iterator()时,Xtend会自动转换为列表。

val segments = line.split('  ').iterator

现在我们使用迭代器,为每个产生的String 创建一个Movie实例。数据类型转换,通过从包装器类型调用静态方法来完成(例如String转为int)。Iterable的其余部分,变成一组类别(categories)。因此,迭代器调用扩展方法IteratorExtensions.toSet(Iterator<T>),以完成其余值的转换。

return new Movie (

segments.next,

Integer.parseInt(segments.next),

Double.parseDouble(segments.next),

Long.parseLong(segments.next),

segments.toSet

)

响应查询

现在我们已经将文本文件解析成了List<Movie>,我们已经准备好对它执行一些查询了。我们使用JUnit来使单个查询可执行并确认其结果。

查询1:动作片数量是多少?

@Test def numberOfActionMovies() {

assertEquals(828,

movies.filter[ categories.contains('Action') ].size)

}

首先,对movies过滤(filter)。lambda表达式检查当前影片的类别是否包含条目'Action'。请注意,不像我们用来将文件中的行转换成movies的lambda,这次我们没有声明一个参数名。所以上面表达式,我们可以这样写:

movies.filter[ movie | movie.categories.contains('Action') ].size

但是由于我们省略了参数名称和垂直条|,所以变量被自动命名it。it是一个隐式变量。它的用法类似于隐式变量this。所以也可以写成这样:

movies.filter[ it.categories.contains('Action') ].size

或甚至更紧凑地写成前面那样:

movies.filter[ categories.contains('Action') ].size

最后我们size也会调用生成的iterable,这也是一个扩展方法。它在实用程序类(utility class )IterableExtensions中定义。

查询2:80年代最好的电影是哪一年上演的?

@Test def void yearOfBestMovieFrom80s() {

assertEquals(1989,

movies.filter[ (1980..1989).contains(year) ].sortBy[ rating ].last.year)

}

在这里,我们过滤1980年至1989年(80年代)范围内的所有电影。操作符“..”又是一个在IntegerExtensions定义的扩展,并返回IntegerRange的实例。操作符重载在第二章中说明。

由此产生的迭代排序,则IterableExtensions.sortBy按movies的rating进行排序。由于它按升序排列,我们从列表中取出最后一个电影并返回其year。

我们也可以按降序排序,还可以列出列表的头:

movies.filter[ (1980..1989).contains(year) ].sortBy[ -rating ].head.year

另一个可能的解决方案是颠倒排序列表的顺序:

movies.filter[ (1980..1989).contains(year) ].sortBy[ rating ].reverseView.head.year

请注意,首先排序,然后取最后或第一个,代价稍大一点。我们可以使用方法reduce更有效地找到最好的电影。你可以自己尝试一下。

前面的例子调用movie.year以及movie.categories,实际上是访问相应的getter方法。

查询3:前两部电影的得票总数是多少?

@Test def void sumOfVotesOfTop2() {

val long sum = movies.sortBy[ -rating ].take(2).map[ numberOfVotes ].reduce[ a, b | a + b ]

assertEquals(47_229L, sum)

}

首先,电影按评级排序,然后我们取最好的两个。接下来,使用map函数将电影列表的numberOfVotes形成新的列表。现在我们有List<Long>,可以通过添加值将其缩小到一个Long。

你也可以用reduce代替map和reduce。你知道怎么做吗?

Xtend官方文档-第一部分相关推荐

  1. [译]1-Key-Value Coding Programming Guide 官方文档第一部分

    Key-Value Coding Programming Guide 官方文档第一部分 2018.9.20 第一次修正 iOS-KVC官方文档第一部分 Key-Value Coding Program ...

  2. Xtend官方文档——第二部分(一)

    第二章 语言文档参考(一) 第一节  Java互操作性 Xtend像Java一样,是一种静态类型的语言.实际上,它完全支持Java的类型系统,包括基本类型,如int或者boolean.数组以及类路径上 ...

  3. 对 Windows 官方文档的一点吐槽

    对 Windows 官方文档的一点吐槽 正文 当你在百度搜 Windows 系统的一些问题,所见之处尽是<小编来教大家><第一步第二步第三步第四步第五步--><方法一方法 ...

  4. 006-基于hyperledger fabric1.4( 官方文档)编写第一个应用【外部nodejs调用】

    一.概述 官方原文地址 Writing Your First Application 如果对fabric网络的基本运行机制不熟悉的话,请看这里. 注意:本教程是对fabric应用以及如何使用智能合约的 ...

  5. 跟着官方文档学DGL框架第一天——DGL概览

    主要参考:https://docs.dgl.ai/tutorials/basics/1_first.html DGL是什么 DGL是一种用于简化图神经网络实现的包,感觉官方文档写得很亲民,打算好好拜读 ...

  6. 文件标识符必须为双精度类型的整数值标量_【翻译】VTK官方文档 - vtk文件格式

    本文翻译自vtk官方文档:vtk_file_format 文末有链接 VTK提供了许多源对象和编写器对象,用于读取和写入流行的数据文件格式,此外,VTK也提供了自己的文件格式.创建一种数据文件格式的主 ...

  7. 深入理解Java 8 Lambda表达式(Oracle官方文档版)

    Java 8 问世三年了,9马上也要问世了,所以,嗯,我要开始学8了-- 官方文档:http://docs.oracle.com/javase/tutorial/java/javaOO/lambdae ...

  8. 《Redis官方文档》用Redis构建分布式锁

    <Redis官方文档>用Redis构建分布式锁 用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现 ...

  9. Swift 4官方文档中文版 The Basic(上)

    Swift学习交流群: 313838956 本群由Guards翻译组创建并维护, 志于给认真想学习Swift的同学打造一个良好的交流圈子. 该文章翻译自Apple官方文档: The Swift 4 P ...

最新文章

  1. c++ socket 结构体
  2. yolo 负样本_目标检测介绍之YOLO与SSD
  3. azkaban mysql参数_azkaban参数详解
  4. C++:值传递、指针传递、引用传递
  5. 老男孩的学生优秀博文及内部教学文章
  6. Python - SimpleHTTPServer and CGIHTTPServer
  7. 怎么用虚拟机搭建云服务器,利用虚拟机搭建云服务器
  8. 特征值、特征向量及相似矩阵
  9. [STM32学习笔记]野火MINI开发板ISP一键下载电路
  10. 基于wifi的物联网技术,主要有哪些优势?
  11. Java Mysql工具类封装
  12. 关于产品的一些思考——八千里科技之谁叫我起床
  13. 【论文阅读 | 冷冻电镜】RELION 4.0 中新的 subtomogram averaging 方法解读
  14. 10 06 01 繁杂
  15. python英文分词库_Python中文分词库jieba,pkusegwg性能准确度比较
  16. 从生活角度学习c++
  17. 5700: 还钱问题
  18. STM32H743使用PA0,PA1作为ADC输入的坑!!
  19. 室内定位系统算法--无线时钟同步的比较
  20. 小信号放大电路的频率特性

热门文章

  1. app通过电商变现方式探讨
  2. win7系统下阿里旺旺无法登陆怎么解决
  3. 红星美羚育儿经:宝宝上火,是奶粉的祸?
  4. 荒野行动8月1日服务器维护,荒野行动手游12月21日服务器维护到几点 12月21日具体开服时间公告...
  5. 视频监控安防平台-国标28181平台(支持国标28181转RTSP/RTMP/HLS/WEBRTC直播)
  6. Win10无法使用内置管理员账户打开应用解决办法
  7. 函数式程序设计为什么至关重要
  8. 金蝶OSF接口(s-HR系统)调用示例
  9. graphpad prism怎么添加图例_Graphpad Prism:如何制作柱状图
  10. hgroup元素与figcaption元素的结合使用