Java 8 Friday:大多数内部DSL已过时

在Data Geekery ,我们喜欢Java。 而且,由于我们真的很喜欢jOOQ的流畅的API和查询DSL ,我们对Java 8将为我们的生态系统带来什么感到非常兴奋。

Java 8星期五

每个星期五,我们都会向您展示一些不错的教程风格的Java 8新功能,这些功能利用了lambda表达式,扩展方法和其他好东西。 您可以在GitHub上找到源代码 。

大多数内部DSL已过时

这是目前市场上最先进的内部DSL之一的供应商的说法。 让我解释:

语言很难

学习新语言(或API)非常困难。 您必须了解所有的关键字,构造,语句和表达式类型等。这对于外部DSL,内部DSL和“常规” API都是正确的,它们本质上是内部DSL,但流畅度较低。

使用JUnit时,人们已经习惯使用hamcrest匹配器 。 它们有六种语言(Java,Python,Ruby,Objective-C,PHP,Erlang)可用,这一事实使它们成为一个不错的选择。 作为特定领域的语言,他们已经建立了易于阅读的习惯用法,例如

assertThat(theBiscuit, equalTo(myBiscuit));
assertThat(theBiscuit, is(equalTo(myBiscuit)));
assertThat(theBiscuit, is(myBiscuit));

阅读此代码时,您将立即“理解”所声明的内容,因为API的读法像prosa。 但是学习用此API编写代码更加困难。 您将必须了解:

  • 所有这些方法来自哪里
  • 存在哪些方法
  • 谁可能使用自定义匹配器扩展了障碍
  • 扩展DSL时的最佳做法是什么

例如,在上面的示例中,三个之间到底有什么区别? 我什么时候应该使用另一个? 是is()检查对象身份吗? equalTo()是否检查对象是否相等?

hamcrest教程继续着以下示例:

public void testSquareRootOfMinusOneIsNotANumber() {assertThat(Math.sqrt(-1), is(notANumber()));
}

您可以看到notANumber()显然是一个自定义匹配器,在实用程序中的某个地方实现了:

public class IsNotANumber
extends TypeSafeMatcher<Double> {@Overridepublic boolean matchesSafely(Double number) {return number.isNaN();}public void describeTo(Description description) {description.appendText("not a number");}@Factorypublic static <T> Matcher<Double> notANumber() {return new IsNotANumber();}
}

尽管这种DSL的创建非常容易,并且可能也很有趣,但是出于简单的原因,开始着手编写和增强自定义DSL是很危险的。 它们绝不比其通用的,功能相同的同类更好-但它们却更难维护。 考虑一下Java 8中的上述示例:

用功能代替DSL

假设我们有一个非常简单的测试API:

static <T> void assertThat(T actual, Predicate<T> expected
) {assertThat(actual, expected, "Test failed");
}static <T> void assertThat(T actual, Predicate<T> expected, String message
) {assertThat(() -> actual, expected, message);
}static <T> void assertThat(Supplier<T> actual, Predicate<T> expected
) {assertThat(actual, expected, "Test failed");
}static <T> void assertThat(Supplier<T> actual, Predicate<T> expected, String message
) {if (!expected.test(actual.get()))throw new AssertionError(message);
}

现在,将hamcrest匹配器表达式与其功能等效项进行比较:

// BEFORE
// ---------------------------------------------
assertThat(theBiscuit, equalTo(myBiscuit));
assertThat(theBiscuit, is(equalTo(myBiscuit)));
assertThat(theBiscuit, is(myBiscuit));assertThat(Math.sqrt(-1), is(notANumber()));// AFTER
// ---------------------------------------------
assertThat(theBiscuit, b -> b == myBiscuit);
assertThat(Math.sqrt(-1), n -> Double.isNaN(n));

有了lambda表达式和经过精心设计的assertThat() API,我可以肯定,您将不再寻找用匹配器表达断言的正确方法。

请注意,不幸的是,我们不能使用Double::isNaN方法引用,因为它与Predicate<Double>不兼容。 为此,我们必须在断言API中执行一些原始类型的魔术,例如

static void assertThat(double actual, DoublePredicate expected
) { ... }

然后可以这样使用:

assertThat(Math.sqrt(-1), Double::isNaN);

好但是…

……您可能会听到自己在说,“但是我们可以将匹配器与lambda和流结合起来”。 是的,我们当然可以。 我现在已经在jOOQ集成测试中做到了。 我想跳过所有不在系统属性中提供的方言列表中的SQL方言的集成测试:

String dialectString = System.getProperty("org.jooq.test-dialects");// The string must not be "empty"
assumeThat(dialectString, not(isOneOf("", null)));// And we check if the current dialect() is
// contained in a comma or semi-colon separated
// list of allowed dialects, trimmed and lowercased
assumeThat(dialect().name().toLowerCase(),// Another matcher hereisOneOf(stream(dialectString.split("[,;]")).map(String::trim).map(String::toLowerCase).toArray(String[]::new))
);

……那也很整洁,对吗?

但是为什么我不干脆写:

// Using Apache Commons, here
assumeThat(dialectString, StringUtils::isNotEmpty);
assumeThat(dialect().name().toLowerCase(),d -> stream(dialectString.split("[,;]")).map(String::trim).map(String::toLowerCase()).anyMatch(d::equals)
);

无需Hamcrest,只需普通的旧lambda和溪流!

现在,当然,可读性只是一个问题。 但是上面的示例清楚地表明,不再需要 Hamcrest匹配器和Hamcrest DSL。 鉴于在接下来的2-3年内,所有Java开发人员中的大多数将非常习惯于每天使用Streams API,而不是非常习惯于使用Hamcrest API,因此,我敦促JUnit维护人员不要使用使用Hamcrest以支持Java 8 API。

哈姆克雷斯特现在被认为是坏人吗?

好吧,它过去已经达到了目的,人们对此已经有所适应。 但是,正如我们在上一篇有关Java 8和JUnit Exception匹配的文章中已经指出的那样,是的,我们确实相信Java的人们在过去的十年中一直在树错误的树。

缺少lambda表达式已导致各种完全膨胀的库 ,现在也有些无用的库 。 许多内部DSL或注释魔术师也受到影响。 不是因为他们不再解决以前遇到的问题,而是因为它们还没有支持Java-8。 Hamcrest的Matcher类型不是功能接口,尽管将其转换为一个接口很容易。 实际上,Hamcrest的CustomMatcher逻辑应该被拉到Matcher接口中,成为默认方法。

使用诸如AssertJ之类的替代方案,事情不会变得更好。该替代方案创建了一个替代DSL,现在它已通过lambda和Streams API变得过时了(就呼叫站点代码冗长而言)。

如果您坚持使用DSL进行测试,那么无论如何Spock可能都是一个更好的选择。

其他例子

Hamcrest只是这种DSL的一个示例。 本文展示了如何通过使用标准的JDK 8构造和几个实用程序方法几乎完全将其从堆栈中删除,无论如何,您可能很快就会在JUnit中使用它们。

Java 8将为上个十年的DSL辩论带来很多新的吸引力,因为Streams API还将大大改善我们看待转换或构建数据的方式。 但是,当前许多DSL尚未为Java 8做好准备,并且尚未以功能性方式进行设计。 对于难以学习的事物和概念,它们有太多的关键字,可以使用函数更好地建模。

该规则的一个例外是jOOQ或jRTF之类的DSL,它们以1:1的方式对实际存在的外部DSL进行建模,继承了所有现有的关键字和语法元素,从而使它们从一开始就很容易学习。

你拿什么

您对上述假设有何看法? 最喜欢的内部DSL是什么,由于Java 8已过时,它可能在未来五年内消失或完全转换?

翻译自: https://www.javacodegeeks.com/2014/06/java-8-friday-most-internal-dsls-are-outdated.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363224.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Starter pom

以下图片是引用书籍内容&#xff1a; 比如你在用boot写一个web项目&#xff0c;在maven中你会导入&#xff1a; <!-- 导入spring boot的web支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-we…

上传图片截图预览控件不显示cropper.js 跨域问题

上传图片到图片服务器&#xff0c;因为域名不同&#xff0c;多以会有跨域问题。 No Access-Control-Allow-Origin header is present on the requested resource. Origin http://img.xxx.com is therefore not allowed access. 照看代码发现&#xff0c;cropper.js里面对图片的…

在Spring JDBC中添加C3PO连接池

连接池是一种操作&#xff0c;其中系统会预先初始化将来要使用的连接。 这样做是因为在使用时创建连接是一项昂贵的操作。 在本文中&#xff0c;我们将学习如何在Spring JDBC中创建C3P0连接池&#xff08;某人未使用休眠&#xff09;。 Pom.xml <dependency><groupI…

在 CentOS/Fedora 下安装 JAVA 环境

介绍 本文介绍如何在 CentOS 7&#xff08;6/6.5&#xff09;、 Fedora、RHEL 上安装 Java。Java是一个流行的软件平台&#xff0c;允许您运行Java应用程序。 本文涵盖了以下Java版本的安装&#xff1a; OpenJDK 8Oracle Java 8先决条件 在开始之前&#xff0c;您应该有一个能够…

小程序: 在同一个文件夹中配置多个页面

1. 可以在同一个文件夹中配置多个页面&#xff08;即相关的放在一个文件夹中&#xff09; 如&#xff1a; 创建一个首页&#xff1a; 在 app.json中配置 -- pages/index/index创建一个首页中的相关页面&#xff1a; 在 app.json中配置 -- pages/index/detail/detail 博客地址…

[欧拉函数] Bzoj P2186 沙拉公主的困惑

Description 大富翁国因为通货膨胀&#xff0c;以及假钞泛滥&#xff0c;政府决定推出一项新的政策&#xff1a;现有钞票编号范围为1到N的阶乘&#xff0c;但是&#xff0c;政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现…

象素图和向量图

象素图和向量图主要的区别是动态和静态的区别 象素图是固定的图&#xff0c;它在图形生成时就已经是由固定的象素点组成了&#xff0c;不可以再变化&#xff0c;所以大小不一样&#xff0c;清晰度不一样&#xff0c; 向量图是动态的图&#xff0c;每次显示都会根据大小绘制本身…

ActiveMQ –经纪人网络解释–第5部分

在前面的第4部分中&#xff0c;我们已经看到了如何使用网络连接器在队列中平衡远程使用者的负载。 在第5部分中&#xff0c;我们将看到如果在某个主题上有并发远程持久订阅者&#xff0c;则相同的配置将如何工作。 考虑以下配置…。 图1&#xff1a;经纪人网络–主题上的负载…

Unity项目导入的error

5.6.3error 如下&#xff1a;An assembly with the same name UnityEngine.UI has already been imported. Consider removing one of the references or sign the assemblyanswer:I deleted all the c# project files at the root of the folder structure and reloaded the p…

小程序: 域名配置

1. 问题 在小程序中&#xff0c;如果我们没有在微信公众平台: 配置 https开头的、备案过的域名话&#xff0c;调用该域名下的接口&#xff0c;就会报错 当然&#xff1a; 如果只是简单的学习下小程序使用的话&#xff0c;可以不校验域名 — 微信开发者工具中&#xff1a; 详情 …

描述符

描述符描述符也是面向进阶的一种&#xff0c;由于它的涉及比较广&#xff0c;所以单独讲。 一、描述符 描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议。 描述符的作用是用来代理另外一个类的属性&#xf…

C++迭代器简介

迭代器是一种检查容器内元素并遍历元素的数据类型。 标准库为每一种标准容器&#xff08;包括 vector&#xff09;定义了一种迭代器类型。迭代器类型提供了比下标操作更通用化的方法&#xff1a;所有的标准库容器都定义了相应的迭代器类型&#xff0c;而只有少数的容器支持下标…

编写干净的测试-被认为有害的新内容

很难为干净的代码找到一个好的定义&#xff0c;因为我们每个人都有自己的单词clean的定义。 但是&#xff0c;有一个似乎是通用的定义&#xff1a; 干净的代码易于阅读。 这可能会让您感到有些惊讶&#xff0c;但是我认为该定义也适用于测试代码。 使测试尽可能具有可读性是我…

所谓经济现象

随想一下&#xff0c;先举出一些基本认知&#xff0c;后面大家会看到这些认知之间的牵扯&#xff0c;已经人在做决策的时候是如何分配权重的&#xff0c;进而产生后续和当今的局面。经济学一点都不难&#xff0c;只是现在人学的是技术上的操作&#xff0c;而不学背后的运作逻辑…

hdu-1277--字典树坑题

hdu-1227 字典树&#xff0c;坑题&#xff01;&#xff01;当字典树练手 Problem Description 我们大家经常用google检索信息&#xff0c;但是检索信息的程序是很困难编写的&#xff1b;现在请你编写一个简单的全文检索程序。 问题的描述是这样的&#xff1a;给定一个信息流文件…

Do not mutate vuex store state outside mutation handlers.

组件代码&#xff1a; selectItem(item,index) {this.selectPlay({list: this.songs,index}) }, ...mapActions([selectPlay ]) mutation 代码&#xff1a; [types.SET_PLAYLIST](state, list) {// 1、state.playlist JSON.parse(JSON.stringify(list))// 2、state.playlist …

硅谷企業面臨新的反壟斷枷鎖

硅谷的公司正面臨著加強反壟斷審查的新階段﹐這是對奧巴馬政府加強執法和持續不斷的海外壓力所做出的反應。 對在其行業中佔據主導地位的企業採取更嚴格的立場可能會考驗這些科技業巨頭在布什政府時期採取的政府關係策略。Associated Press奧巴馬政府任命的司法部負責反壟斷執法…

Spring Java配置:会话超时

当您可以使用基于Java的配置开发Spring应用程序时&#xff0c;我们生活在一个美好的时光。 不再有多余的XML代码&#xff0c;只有纯Java代码。 在本文中&#xff0c;我想讨论一个关于Spring应用程序中会话管理的热门话题。 更确切地说&#xff0c;我将以Java配置样式讨论会话超…

怎样去掉警告 log4j:WARN No appenders could be found for logger

最近在作项目的时候&#xff0c;用到了 HttpClient&#xff0c;用它向 HTTP server 发送请求并处理返回的页面数据。 我的应用类间接调用 HttpClient。在运行的时候&#xff0c;程序打印出了如下警告信息&#xff1a; log4j:WARN No appenders could be found for logger log…

这首歌【好听】到哭出来

转载于:https://www.cnblogs.com/Agnel-Cynthia/p/10662886.html