知识大全 Java开发者的Scala指南: Scala+Twitter=Scitter
Posted 消息
篇首语:情况是在不断地变化,要使自己的思想适应新的情况,就得学习。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java开发者的Scala指南: Scala+Twitter=Scitter相关的知识,希望对你有一定的参考价值。
Java开发者的Scala指南: Scala+Twitter=Scitter 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
抽象地讨论 Scala 是一件有趣的事情 但对于本专栏的大多数读者而言 需要通过实践才能理解理论和应用之间的区别 在本期文章中 Ted Neward 将使用 Scala 为客户构建基础框架 用于访问流行的微型博客系统 Twitter
Twitter 迅速占领了 Internet 市场 您肯定知道这个出色的社交网络工具允许订阅者提供关于他们自身以及当前正在执行的任务的简要状态更新 追随者将接收到他们的 Twitter 提要 的更新 这与博客将更新生成到博客阅读者的提要中极为类似
关于本系列
Ted Neward 将深入探讨 Scala 编程语言 并带领您一路随行 在本 系列 中 您将学习最新的热点以及 Scala 的语言功能 Scala 代码和 Java&# ; 代码将在必要时同时出现以方便进行比较 但您会发现 Scala 中的许多内容都与 Java 没有直接关系 — 这便是 Scala 的魄力所在!毕竟 如果 Java 能够做到 为什么还要大费周折来学习 Scala 呢?
就其本身而言 Twitter 是对社交网络的有趣讨论 并且是用户之间的新一代 高度互联 它具备您能想到的所有优点和缺点
由于 Twitter 很早就发布了其 API 因此大量 Twitter 客户机应用程序涌入到 Internet 上 由于该 API 主要建立在直观和易于理解的基础上 因此许多开发人员都发现有必要构建一个自己的 Twitter 客户机 这与学习 Web 技术的开发人员构建自己的博客服务器极为类似
考虑到 Scala 的功能性(这看上去能很好地协同 Twitter 的 REST 式特性)以及非常出众的 XML 处理特性 因此尝试构建一个用于访问 Twitter 的 Scala 客户机库应该是一个非常不错的体验
何为 Twitter?
在详细讨论之前 我们先来看看 Twitter API
简单来说 Twitter 是一个 微型博客 — 关于您自己的简短个性化提要 不超过 个字符 任何 追随者 都可以通过 Web 更新 RSS 文本消息等方式接收它们 ( 字符的限制完全来自文本消息 它是 Twitter 的主要来源渠道 并受到类似的限制)
最具 REST 特征 是什么意思?
一些读者会对我所使用的最具 REST 特征 短语感到好奇;这需要一些说明 Twitter API 试图符合 Representational State Transfer (REST) 的设计原则 并且在很大程度上说它做到了 该思想的创造者 Roy Fielding 可能不同意 Twitter 使用这个术语 但实现来说 Twitter 的方法将适合大多数人的 REST 定义 我只希望避免关于 REST 定义的激烈争论 因此 我使用了限定词 最
从实际的角度来说 Twitter 是一个最具 REST 特征 的 API 您可以使用一些种类的消息格式 — XML ATOM RSS 或 JSON — 来发送或从 Twitter 服务器接收消息 不同的 URL 与不同的消息和它们所需及可选的消息部分相结合 可以发起不同的 API 调用 例如 如果您希望接收 Twitter 上所有人的所有 Tweets (Twitter 更新)的完整列表(也称作 公共时间轴 ) 您需要准备一个 XML ATOM RSS 或 JSON 消息 将它发送给合适的 URL 并采用与 Twitter 网站()上相同的格式来使用结果
public_timeline
返回设定了自定义用户图标的
非保护用户的 条最新状态 不需要身份验证
注意 公共时间轴将缓存 秒钟
因此频繁请求它不再浪费资源
URL _timeline format
格式 xml json rss atom
方法 GET
API 限制 不适用
返回 状态元素列表
从编程的角度来说 这意味着我们给 Twitter 服务器发送一个简单的 GET HTTP 请求 并且我们将获取一组封装在 XML RSS ATOM 或 JSON 消息中的 状态 消息 Twitter 站点将 状态 消息定义为类似清单 所示的内容
清单 您好世界 您在哪里?
<feed xml:lang= en US xmlns= > <title>Twitter / tedneward</title> <id>tag: :Status</id> <link type= text/ rel= alternate /> <updated> T : : + : </updated> <subtitle>Twitter updates from Ted Neward / tedneward </subtitle> <entry> <title>tedneward: @kdellison Happens to the best of us </title> <content type= >tedneward: @kdellison Happens to the best of us </content> <id>tag: :;/id> <published> T : : + : </published> <updated> T : : + : </updated> <link type= text/ rel= alternate /> <link type= image/png rel= image _production/profile_images/ /javapolis_normal png /> <author> <name>Ted Neward</name> <uri>;/uri> </author> </entry> </feed>
部的话)都很直观 因此不再赘述
由于我们可以采用三种基于 XML 的格式使用 Twitter 消息 以及 Scala 具备一些非常强大的 XML 特性 包括 XML 字面值和类似 XPath 的查询语法 API 因此编写可以发送和接收 Twitter 消息的 Scala 库只需要一些基础的 Scala 编码工作 举例来说 通过 Scala 使用清单 消息来提取状态更新的标题或内容可以利用 Scala 的 XML 类型和 \\ 及 \\\\ 方法 如清单 所示
清单 您好 Ted 您在哪里?
<![CDATA[ package tedneward scitter test class ScitterTest import junit _ Assert _ @Test def simpleAtomParse = val atom = <feed xml:lang= en US xmlns= > <title>Twitter / tedneward</title> <id>tag: :Status</id> <link type= text/ rel= alternate /> <updated> T : : + : </updated> <subtitle>Twitter updates from Ted Neward / tedneward </subtitle> <entry> <title>tedneward: @kdellison Happens to the best of us </title> <content type= >tedneward: @kdellison Happens to the best of us </content> <id>tag: : ;/id> <published> T : : + : </published> <updated> T : : + : </updated> <link type= text/ rel= alternate /> <link type= image/png rel= image _production/profile_images/ /javapolis_normal png /> <author> <name>Ted Neward</name> <uri>;/uri> </author> </entry> </feed> assertEquals(atom \\\\ entry \\ title tedneward: @kdellison Happens to the best of us ) ]]>
有关 Scala 的 XML 支持的更多详细信息 请参阅 Scala 和 XML (参见 参考资料)
实际上 使用原始 XML 本身并不是一个有趣的练习 如果 Scala 的宗旨是让我们的生活更加轻松 那么可以创建一个或一组专用于简化 Scala 消息发送和接收任务的类 作为其中一个目标 应该能够在 普通 Java 程序中方便地使用库(这意味着可以方便地从任何可理解普通 Java 语义的环境中来访问它 比如说 Groovy 或 Clojure)
API 设计
在深入了解 Scala/Twitter 库的 API 设计之前(根据同事 ThoughtWorker Neal Ford 的建议 我将它称作 Scitter ) 需要明确一些需求
首先 Scitter 显然会对网络访问有一些依赖 — 并且可扩展到 Twitter 服务器 — 这会使测试变得非常困难
其次 我们需要解析(和测试)Twitter 发回的各种格式
第三 我们希望隐藏 API 内部各种格式之间的差异 以便客户机不需要担心已记录的 Twitter 消息格式 但是可以仅使用标准类
最后 由于 Twitter 依赖 通过身份验证的用户 才能使用大量 API 因此 Scitter 库需要适应 验证 和 未验证 API 之间的差异 而不会让事情变得过于复杂
网络访问需要一些形式的 HTTP 通信 以便联系 Twitter 服务器 虽然我们可以使用 Java 库本身(特别是 URL 类及其同胞) 但由于 Twitter API 需要大量请求和响应主体连接 因此可以更加轻松地使用不同的 HTTP API 特别是 Apache Commons HttpClient 库 为了更便于测试客户机 API 实际通信将隐藏在一些 API 内部的 Scitter 库中 以便能够更加轻松地切换到另一个 HTTP 库(其必要性不太容易想到) 并能模拟实际网络通信以简化测试(其作用很容易想到)
结果 第一个测试是 Scala 化 HttpClient 调用 以确保基本通信模式就位;注意 由于 HttpClient 依赖另外两个 Apache 库(Commons Logging 和 Commons Codec) 因此还需要在运行时提供这些库;对于那些希望开发相似种类代码的读者 确保类路径中包括所有三个库
由于最易于使用的 Twitter API 是测试 API
因此在请求格式中返回 ok 并附带 OK HTTP 状态码
我们将使用它作为 Scitter 测试中的保留条款 它位于 URL (其中 format 为 xml 或 json ;至于目前 我们将选择使用 xml ) 并且仅有的支持 HTTP 方法是 GET HttpClient 代码简明易懂 如清单 所示
清单 Twitter PING!
package tedneward scitter test class ExplorationTests // import mons _ methods _ params _ cookie _ @Test def callTwitterTest = val testURL = // HttpClient API val client = new HttpClient() val method = new GetMethod(testURL) method getParams() setParameter(HttpMethodParams RETRY_HANDLER new DefaultHttpMethodRetryHandler( false)) client executeMethod(method) val statusLine = method getStatusLine() assertEquals(statusLine getStatusCode() ) assertEquals(statusLine getReasonPhrase() OK )
此代码中最重要的一部分是 HttpClient 样板 — 感兴趣的读者应该查阅 HttpClient API 文档了解详细信息 假设连接到公共 Internet 的网络可用(并且 Twitter 并未修改其公共 API) 那么该测试应该能顺利通过
鉴于此 我们详细分析 Scitter 客户机的第一部分 这意味着我们需要解决一个设计问题 如何构建 Scitter 客户机来处理经过验证和未经过验证的调用 目前 我将采用典型的 Scala 方式 假定验证是 按对象 执行的 因此将需要验证的调用放在类定义中 并在未验证的调用放在对象定义中
清单 Scitter test
package tedneward scitter /** * Object for consuming non specific Twitter feeds such as the public timeline * Use this to do non authenticated requests of Twitter feeds */ object Scitter import mons _ methods _ params _ cookie _ /** * Ping the server to see if it s up and running * * Twitter docs say: * test * Returns the string ok in the requested format with a OK HTTP status code * URL: * Formats: xml json * Method(s): GET */ def test : Boolean = val client = new HttpClient() val method = new GetMethod( ) method getParams() setParameter(HttpMethodParams RETRY_HANDLER new DefaultHttpMethodRetryHandler( false)) client executeMethod(method) val statusLine = method getStatusLine() statusLine getStatusCode() == /** * Class for consuming authenticated user Twitter APIs Each instance is * thus tied to a particular authenticated user on Twitter and will * behave accordingly (according to the Twitter API documentation) */ class Scitter(username : String password : String)
目前 我们将网络抽象放在一边 — 稍后 当离线测试变得更加重要时再添加它 当我们更好地理解如何使用 HttpClient 类时 这还将帮助避免 过度抽象 网络通信
由于已经明确区分了验证和未验证 Twitter 客户机 因此我们将快速创建一个经过验证的方法 看上去 Twitter 提供了一个可验证用户登录凭证的 API 再次 HttpClient 代码将类似于之前的代码 除了将用户名和密码传递到 Twitter API 中之外
这引出了 Twitter 如何验证用户的概念 快速查看 Twitter API 页面后 可以发现 Twitter 使用的是一种 Stock HTTP 验证方法 这与任何经过验证的资源在 HTTP 中的方法相同 这意味着 HttpClient 代码必须提供用户名和密码作为 HTTP 请求的一部分 而不是作为 POST 的主体 如清单 所示
清单 您好 Twitter 是我!
package tedneward scitter test class ExplorationTests def testUser = TwitterUser def testPassword = TwitterPassword @Test def verifyCreds = val client = new HttpClient() val verifyCredsURL = _credentials xml val method = new GetMethod(verifyCredsURL) method getParams() setParameter(HttpMethodParams RETRY_HANDLER new DefaultHttpMethodRetryHandler( false)) client getParams() setAuthenticationPreemptive(true) val defaultcreds = new UsernamePasswordCredentials(testUser testPassword) client getState() setCredentials(new AuthScope( AuthScope ANY_REALM) defaultcreds) client executeMethod(method) val statusLine = method getStatusLine() assertEquals( statusLine getStatusCode()) assertEquals( OK statusLine getReasonPhrase())
注意 要让此测试顺利通信 用户名和密码字段将需要输入 Twitter 能接收的内容 — 我在开发时使用了自己的 Twitter 用户名和密码 但显然您需要使用自己设定的用户名和密码 注册新的 Twitter 帐户相当简单 因此我假定您已经拥有一个帐户 或者知道如何注册(很好 我会等待完成此任务)
完成后 使用用户名和密码构造函数参数将它映射到 Scitter 类非常简单 如清单 所示
清单 Scitter verifyCredentials
package tedneward scitter import mons _ auth _ methods _ params _ // /** * Class for consuming authenticated user Twitter APIs Each instance is * thus tied to a particular authenticated user on Twitter and will * behave accordingly (according to the Twitter API documentation) */ class Scitter(username : String password : String) /** * Verify the user credentials against Twitter * * Twitter docs say: * verify_credentials * Returns an HTTP OK response code and a representation of the * requesting user if authentication was successful; returns a status * code and an error message if not Use this method to test if supplied * user credentials are valid * URL: _credentials format * Formats: xml json * Method(s): GET */ def verifyCredentials : Boolean = val client = new HttpClient() val method = new GetMethod( ) method getParams() setParameter(HttpMethodParams RETRY_HANDLER new DefaultHttpMethodRetryHandler( false)) client getParams() setAuthenticationPreemptive(true) val creds = new UsernamePasswordCredentials(username password) client getState() setCredentials( new AuthScope( AuthScope ANY_REALM) creds) client executeMethod(method) val statusLine = method getStatusLine() statusLine getStatusCode() ==
清单 中相应的 Scitter 类测试也相当简单
清单 测试 Scitter verifyCredentials
package tedneward scitter test class ScitterTests import junit _ Assert _ import tedneward scitter _ def testUser = TwitterUsername def testPassword = TwitterPassword // @Test def verifyCreds = val scitter = new Scitter(testUser testPassword) val result = scitter verifyCredentials assertTrue(result)
不算太糟 库的基本结构已经成形 但显然还有很长的路要走 特别是因为目前实际上未执行任何特定于 Scala 的任务 — 在面向对象设计中 库的构建并不像练习那样简单 因此 我们开始使用一些 XML 并通过更加合理的格式将它返回
从 XML 到对象
现在可以添加的最简单的 API 是 public_timeline 它收集 Twitter 从所有用户处接收到的最新的 n 更新 并返回它们以便于进行使用 与之前讨论的另外两个 API 不同 public_timeline API 返回一个响应主体(而不是仅依赖于状态码) 因此我们需要分解生成的 XML/RSS/ATOM/ 然后将它们返回给 Scitter 客户机
现在 我们编写一个探索测试 它将访问公共提要并将结果转储到 stdout 以便进行分析 如清单 所示
清单 大家都在忙什么?
package tedneward scitter test class ExplorationTests // @Test def callTwitterPublicTimeline = val publicFeedURL = _timeline xml // HttpClient API val client = new HttpClient() val method = new GetMethod(publicFeedURL) method getParams() setParameter(HttpMethodParams RETRY_HANDLER new DefaultHttpMethodRetryHandler( false)) client executeMethod(method) val statusLine = method getStatusLine() assertEquals(statusLine getStatusCode() ) assertEquals(statusLine getReasonPhrase() OK ) val responseBody = method getResponseBodyAsString() System out println( callTwitterPublicTimeline got ) System out println(responseBody)
运行后 结果每次都会有所不同 因为公共 Twitter 服务器上有许多用户 但通常应与清单 的 JUnit 文本文件转储类似
清单 我们的 Tweets 结果
<statuses type= array > <status> <created_at>Tue Mar : : + </created_at> <id> </id> <text>She really is ;/text> <source><a >itterrific</a> </source> <truncated>false</truncated> <in_reply_to_status_id></in_reply_to_status_id> <in_reply_to_user_id></in_reply_to_user_id> <favorited>false</favorited> <user> <id> </id> <name>Brittanie</name> <screen_name>brittaniemarie</screen_name> <description>I m a bright character I suppose </description> <location>Atlanta or Philly </location> <profile_image_url>_production/profile_images/ /goodish_normal jpg</profile_image_url> <url>;/url> <protected>false</protected> <followers_count> </followers_count> </user> </status> <status> <created_at>Tue Mar : : + </created_at> <id> </id> <text>Number of my four life principles Life is fun and rewarding </text> <source>web</source> <truncated>false</truncated> <in_reply_to_status_id></in_reply_to_status_id> <in_reply_to_user_id></in_reply_to_user_id> <favorited>false</favorited> <user> <id> </id> <name>Dale Greenwood</name> <screen_name>Greeendale</screen_name> <description>Vegetarian Eat and use only anics Love helping people bee prosperous</description> <location>Melbourne Australia</location> <profile_image_url>_production/profile_images/ /Dock_normal jpg</profile_image_url> <url>;/url> <protected>false</protected> <followers_count> </followers_count> </user> </status> (A lot more have been snipped) </statuses>
通过查看结果和 Twitter 文档可以看出 调用的结果是一组具备一致消息结构的简单 状态 消息 使用 Scala 的 XML 支持分离结果相当简单 但我们会在基本测试通过后立即简化它们 如清单 所示
清单 大家都在忙什么?
package tedneward scitter test class ExplorationTests // @Test def simplePublicFeedPullAndParse = val publicFeedURL = _timeline xml // HttpClient API val client = new HttpClient() val method = new GetMethod(publicFeedURL) method getParams() setParameter(HttpMethodParams RETRY_HANDLER new DefaultHttpMethodRetryHandler( false)) val statusCode = client executeMethod(method) val responseBody = new String(method getResponseBody()) val responseXML = scala xml XML loadString(responseBody) val statuses = responseXML \\\\ status for (n < statuses elements) n match case contents @ _* => System out println( Status: ) contents foreach((c) => c match case t @ _* => System out println( \\tText: + t text trim) case contents @ _* => contents foreach((c ) => c match case u => System out println( \\tUser: + u text trim) case _ => () ) case _ => () ) case _ => () // or if you prefer System out println( Unrecognized element! )
随着示例代码模式的变化 这并不值得推荐 — 这有点类似于 DOM 依次导航到各个子元素 提取文本 然后导航到另一个节点 我可以仅执行两个 XPath 样式的查询 如清单 所示
清单 替代解析方法
for (n < statuses elements) val text = (n \\\\ text ) text val screenName = (n \\\\ user \\ screen_name ) text
这显然更加简短 但它带来了两个基本问题
我们可以强制 Scala 的 XML 库针对每个元素或子元素遍历一次图 其速度会随时间减慢
我们仍然需要直接处理 XML 消息的结构 这是两个问题中最为重要的
也就是说 这种方式不具备可伸缩性 — 假设我们最终对 Twitter 状态消息中的每个元素都感兴趣 我们将需要分别从各状态中提取各个元素
这又造成了另一个与各格式本身相关的问题 记住 Twitter 可以使用四种不同的格式 并且我们不希望 Scitter 客户机需要了解它们之间的任何差异 因此 Scitter 需要一个能返回给客户机的中间结构 以便未来使用 如清单 所示
清单 Breaker 您的状态是什么?
abstract class Status val createdAt : String val id : Long val text : String val source : String val truncated : Boolean val inReplyToStatusId : Option[Long] val inReplyToUserId : Option[Long] val favorited : Boolean val user : User
这与 User 方式相类似 考虑到简洁性 我就不再重复了 注意 User 子元素有一个有趣的问题 — 虽然存在 Twitter 用户类型 但其中内嵌了一个可选的 最新状态 状态消息还内嵌了一个用户 对于这种情况 为了帮助避免一些潜在的递归问题 我选择创建一个嵌入在 Status 内部的 User 类型 以反映所出现的 User 数据;反之亦然 Status 也可以嵌入在 User 中 这样可以明确避免该问题 (至少 在没发现问题之前 这种方法是有效的)
现在 创建了表示 Twitter 消息的对象类型之后 我们可以遵循 XML 反序列化的公共 Scala 模式 创建相应的对象定义 其中包含一个 fromXml 方法 用于将 XML 节点分离到对象实例中 如清单 所示
清单 分解 XML
/** * Object wrapper for transforming (format) into Status instances */ object Status def fromXml(node : scala xml Node) : Status = new Status val createdAt = (node \\ created_at ) text val id = (node \\ id ) text toLong val text = (node \\ text ) text val source = (node \\ source ) text val truncated = (node \\ truncated ) text toBoolean val inReplyToStatusId = if ((node \\ in_reply_to_status_id ) text != ) Some((node \\ in_reply_to_status_id ) text toLong) else None val inReplyToUserId = if ((node \\ in_reply_to_user_id ) text != ) Some((node \\ in_reply_to_user_id ) text toLong) else None val favorited = (node \\ favorited ) text toBoolean val user = User fromXml((node \\ user )( ))
其中最强大的一处是 它可以针对 Twitter 支持的其他任何格式进行扩展 — fromXml 方法可以在分解节点之前检查它是否保存了 XML RSS 或 Atom 类型的内容 或者 Status 可以包含 fromXml fromRss fromAtom 和 fromJson 方法 实际上 后一种方法是我的优先选择 因为它会平等对待基于 XML 的格式和 JSON(基于文本)格式
好奇和细心的读者会注意到在 Status 及其内嵌 User 的 fromXml 方法中 我使用的是 XPath 样式的分解方法 而不是之前建议的遍历内嵌元素的方法 现在 XPath 样式的方法看上去更易于阅读 但幸运的是 我后来改变了注意 良好的封装仍然是我的朋友 — 我可以在随后修改它 Scitter 外部的任何人都不会知道
注意 Status 内部的两个成员如何使用 Option[T] 类型;这是因为这些元素通常排除在 Status 消息外部 并且虽然元素本身会出现 但它们显示为空(类似于
现在已经可以轻而易举地使用公共时间轴
清单 分解公共时间轴
@Test def simplePublicFeedPullAndDeserialize = val publicFeedURL = _timeline xml // HttpClient API val client = new HttpClient() val method = new GetMethod(publicFeedURL) method getParams() setParameter(HttpMethodParams RETRY_HANDLER new DefaultHttpMethodRetryHandler( false)) val statusCode = client executeMethod(method) val responseBody = new String(method getResponseBody()) val responseXML = scala xml XML loadString(responseBody) val statuses = responseXML \\\\ status for (n < statuses elements) val s = Status fromXml(n) System out println( \\t @ + s user screenName + wrote + s text)
显然 这看上去更加简洁 并且易于使用
将所有这些结合到 Scitter 单一实例中相当简单 仅涉及执行查询 解析各个 Status 元素以及将它们添加到 List[Status] 实例中 如清单 所示
清单 Scitter publicTimeline
package tedneward scitter import mons _ auth _ methods _ params _ import scala xml _ object Scitter // /** * Query the public timeline for the most recent statuses * * Twitter docs say: * public_timeline * Returns the most recent statuses from non protected users who have set * a custom user icon Does not require authentication Note that the * public timeline is cached for seconds so requesting it more often than * that is a waste of resources * URL: _timeline format * Formats: xml json rss atom * Method(s): GET * API limit: Not applicable * Returns: list of status elements */ def publicTimeline : List[Status] = import llection mutable ListBuffer val client = new HttpClient() val method = new GetMethod( _timeline xml ) method getParams() setParameter(HttpMethodParams RETRY_HANDLER new DefaultHttpMethodRetryHandler( false)) client executeMethod(method) val statusLine = method getStatusLine() if (statusLine getStatusCode() == ) val responseXML = XML loadString(method getResponseBodyAsString()) val statusListBuffer = new ListBuffer[Status] for (n < (responseXML \\\\ status ) elements) statusListBuffer += (Status fromXml(n)) statusListBuffer toList else Nil
在实现功能全面的 Twiter 客户机之前 我们显然还有很长的路要走 但到目前为止 我们已经实现基本的行为
结束语
构建 Scitter 库的工作进展顺利;目前 Scitter 测试实现相对比较简单 与产生 Scitter API 的探索测试相比时尤为如此 外部用户不需要担心 Twitter API 或者它的各种格式的复杂性 虽然目前测试 Scitter 库有点困难(对单元测试而言 依赖网络并不是个好方法) 但我们会及时解决此问题
注意 我故意在 Twitter API 中维持了面向对象的感觉 秉承了 Scala 的精神 — 因为 Scala 支持大量功能特性并不表示我们要放弃 Java 结构采用的对象设计方法 我们将接受有用的功能特性 同时仍然保留适用的 旧方法
这并不是说我们在此处提供的设计是解决问题最好的方法 只能说这是我们决定采用的设计方法;并且 因为我是本文的作者 所以我采用的是自己的方式 如果不喜欢 您可以编写自己的库和文章(并将 URL 发送给我 我会在未来的文章中向您发起挑战) 事实上 在未来的文章中 我会将所有这些封装在一个 Scala sbaz 包中 并上传到网上供大家下载
cha138/Article/program/Java/Javascript/201311/25296相关参考
知识大全 面向Java开发人员的Scala指南: Scala控制结构内部揭密
面向Java开发人员的Scala指南:Scala控制结构内部揭密 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起
知识大全 面向Java开发人员的Scala指南: 深入了解Scala并发性 了解 Scala 如何简化并发编
面向Java开发人员的Scala指南:深入了解Scala并发性了解Scala如何简化并发编 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后
知识大全 面向Java开发人员的Scala指南: 深入了解Scala并发性 了解 actor 如何提供新的应
面向Java开发人员的Scala指南:深入了解Scala并发性了解actor如何提供新的应 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后
面向Java开发人员的Scala指南:实现继承 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! S
知识大全 面向Java开发人员的Scala指南: 增强Scitter库
面向Java开发人员的Scala指南:增强Scitter库 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一
知识大全 面向Java开发人员的Scala指南: 关于特征和行为
面向Java开发人员的Scala指南:关于特征和行为 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
知识大全 面向Java开发人员的Scala指南: 面向对象的函数编程
面向Java开发人员的Scala指南:面向对象的函数编程 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下
知识大全 面向Java开发人员的Scala指南: 包和访问修饰符
面向Java开发人员的Scala指南:包和访问修饰符 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
知识大全 面向Java开发人员的Scala指南: 构建计算器,第1 部分
面向Java开发人员的Scala指南:构建计算器,第1部分 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一
知识大全 面向Java开发人员的Scala指南: 构建计算器,第 2 部分
面向Java开发人员的Scala指南:构建计算器,第2部分 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一