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
總結
以上是生活随笔為你收集整理的Java 8 Friday:大多数内部DSL已过时的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ddos需要多少钱(ddos软件多少钱)
- 下一篇: 在Spring JDBC中添加C3PO连