java:8最小镜像
在1996年至2002年之间,我用Java编写了成千上万行代码。我用Java 1.0到Java 1.4编写了Web框架,电子表格以及更多内容。
与90年代中期(预模板)的C ++相比,Java是一种完全令人惊奇的语言。 JVM是所有计算机语言的最佳运行时。
漫长的奇异之旅
从2002年开始,我开始做C#。 然后是露比 然后是Scala。 一些Haskell,最近,我做了很多Clojure。
因此,我今年完成的Java 1.5 / Generics数量非常有限。
有一个Java演出
今年,我参加了一场演出,写了一些非常有趣的代码(编写了一个编译器)。 但是,客户是一家Java商店。 该项目已经具有Java基础。 客户坚决认为该项目全部用Java来完成……不是Scala……不是Clojure……不是JRuby,而是Java。
因此,过去6个月中,我花了数千行Java代码。 我已经看到Java在过去10年中如何发展,这令人震惊。 令人震惊的Java变得多么糟糕。
基本上,Java毫无意义。 据我所知,泛型将给定程序的总字符数增加约20%-30%。 虽然Scala的类型(带有类型推断)与Ruby相比是纯正的(在我看来,陪审团无法确定Scala的类型系统的重量与它相对于类型较少的Clojure的价值。)Java令人惊讶的冗长,视觉分散,丑陋的东西我可以想到泛型不值得在类型检查与Java 1.4的边际改进之间进行。
因此,我将介绍我认为可以使Java更好而又不会破坏语言的东西。
这不是“ Scala更好的帖子”
请注意,该帖子不是“ Scala更好”的帖子。 尽管文章中的某些想法来自Scala,但我认为Scala(或Clojure)不能替代Java。 Scala只是一种语言,我已经看到大量的Scala滥用。
此外,我认为Scala在很大程度上已经遭受了Java的同样痛苦(增加了语言的负担和复杂性(主要是通过Scala的类型系统)来解决边际问题),考虑到两种语言,这不足为奇的血统。
有些东西可能是在JDK 8中提出或提出的
这些是我的想法。 我不是JCP地区的球员。 感谢与Sam Pullara的出色午餐,我了解Java 8中的lambda。 但是我没有处理太多的JCP流量,因此JCP提案可能涵盖了这些想法。
默认公开
除非有明确的可见性级别,否则将所有声明默认为public
。 是的,我知道这会破坏现有的一些代码,但是让我们将默认值设置为正确的值即可。
为什么? 由于我们的代码中包含的噪声越少,信号越突出。
最后一个表达式是返回值
信号变得更有价值的另一个地方不再需要return
关键字。 最后一个表达式成为返回值:
int plusOne(int x) {x + 1;}
仅当方法中没有return
语句时才适用。 因此,如果您打算将return
用于控制流编程,则必须明确。 但是对于小型,简单的方法,摆脱return
意味着更少的视觉噪音。
块表达式
花括号中的任何内容都是一个块表达式,而不是一个块语句。 这意味着如果花括号的东西可以是一个表达式,则将其视为此类。
String s = {
var d = new Date();
"The current date is "+d;
}
某种类型推断
我希望看到自动分配推断。 基本上:
var name = "David"; // it's a String, duh
我们不需要使var
为关键字。 基本上,类型var
成为“推断类型”类型。
和基本的左侧参数类型推断(请注意,IntelliJ已经使用此语法):
List<String> stuff = new ArrayList<~>();
如果返回值只有一条路径(除了方法的最后一行,没有return
语句),则返回类型推断:
plusOne(int x) // it's an int
{
x + 1;
}
以上所有更改都可以使用编译器已知的数据来完成。 无需花哨的算法。 只是减少了程序中重复单词的数量……而通过泛型类型推断,无论如何,IDE都已经显示了它们。
更好的平等测试
将===
添加为equals
方法的别名,但要求===
的右侧与右侧协变。
另外,将!==
添加为!equals
。
具有元数据的简单,不可变的数据结构
用Java表示简单数据是一个巨大的痛苦。 是的,IDE在创建getter / setter方面大有帮助。 但是最终,我们的许多程序都包含原始数据。 因此,我建议向Java添加内部数据结构。
这些是Scala的案例类与Clojure的元数据工具的组合。
struct
只能在顶级公共类中。
例如:
public class MyStuff {
struct Name(firstName = "David", lastName = "Pollak",
age = 49, Date birthday = null)
public static boolean funWithNames() {
var archer = Name("Archer").age(10);
var tessa = Name().firstName("Tessa").lastName("kitten").
age(1);
assert(tessa.age === 1);
assert(tessa.getAge() === 1);
archer !== tessa;
}
public static void metaData() {
var david = Name("David", "Pollak");
Name d2 = david.setMeta("geek", "true");
assert(david === d2); // metadata not part of equality testing
assert(david != d2); // object instances not the same
assert(david.getMeta("geek") === null);
assert(d2.getMeta("geek") === "true");
}
}
你从struct
得到什么?
- 不可变对象的创建,无需使用每个参数的
new
且具有位置构造函数,以及简单的名义上的创建和新值链接。 - 与每个
struct
相关联的元数据的Map<String, String>
。 - 每个字段的默认值。 这允许添加字段,并且带有附加参数的新版本库不会破坏访问旧版本的代码。
- 一个
toString
方法,它输出字段名称和值。 - 一个正确实现的
equals
方法,可以通过对空字段的适当处理来进行所有字段比较。 - 计算哈希码的
hashCode
方法(如果已知所有字段都是不可变的,则应将其缓存)。 - 字段级访问器方法。
- 每字段复印机:
field(param)
这允许创建具有新值的新实例。 元数据已复制。 - 每个
struct
都有大量的元数据,包括字段名称列表,每个字段的类型。 该元数据可用于快速,高效,自动生成的一组序列化器/反序列化器(例如JSON,JDBC,XML)。
另外,请注意定义的语法。 如果可以,则推断类型。
对于每个包含struct
类,将有一个ClassName.struct
接口。 该接口由所有struct
实现,并且该接口包含所有共享字段。 例如:
class People {
struct Parent(String name = null, List<People.struct> kids = null)
struct Kid(String name = null, Parent parent = null)
String getName(struct person) {person.name;}
}
注解也可以完成很多事情(例如,增强struct
的JSON可序列struct
等)
但是,采用轻量级的方法在语言级别定义数据模式可以使代码编写更快,更易于维护并且更具可读性。
精铸
Java转换过于冗长且容易出错。 使用if
/ instanceof
/ cast模式需要大量代码,并且非常容易出错,因为该类被指定了两次……一次在测试中,一次在强制转换中。
我们可以从Scala借用我最喜欢的功能之一:模式匹配,但是只需执行以下操作:
String testIt(Object o) {
switch o {
String s: s;
Number n: "It's a number: "+n;
Date d if d.millis() > 0: {
var formattedDate = formatDate(d);
"It's a modern date: "+formattedDate;
}
default: "No clue";
}
}
好吧...我们有什么? 该类已测试。 如果类是匹配项,则将其分配给变量(仅具有行范围)。 接下来,运行警卫,看看是否应该采取这种行动。 如果是这样,请运行:
右侧的表达式。
请注意,这种形式的切换是一种表达方式,而不是一条声明。 另外,请注意,不会掉线。
那么,这还能使事情变得更容易吗?
String whatSize(int i) {
switch i {
v if s < 10 : "small";
v if s < 100 : "medium";
default: "large";
}
}
接下来我们可以将它应用于struct
s(不,这不是模式匹配):
String aboutPerson(People.struct p) {
switch p all {
Parent p: "A parent named "+p.name+" #"+p.kids.size();
Kid k: "A kid with "+(k.parent.kids.size() - 1)+" sibs";
}
}
express之后的all
关键字表示必须匹配。 如果将新的struct
添加到类中,这将很有用,因为所有在该struct
上打开的位置都将标记一个编译时错误。
不变的收藏
Java迫切需要一个出色的不可变集合包。
基本上,该软件包是Clojure出色的Map
和Vector
类的纯粹复制品。 我们不需要很多花哨的Scala风格的收藏。
不实现java.util.List
或java.util.Map
不可变集合。 基本上,这些集合将是独立的。
与JDK 8 lambda结合使用时,我会从Scala和Clojure那里获得我在收集操作方面的全部心血。
所以你有它
所以你有它。 我认为以上内容将使Java更易于处理语言。 它将减少冗长。 它将允许将数据作为相当普遍的数据进行处理,尤其是在编写将数据编组进出系统的服务时。
上述更改将减少Java的冗长性,而不会显着降低Java的“讲述故事”代码。 而且,是的,有可能编写相当难以理解的Scala代码。 我们不想去Scala去的地方。
我还想看什么? 按名称调用参数(我不知道它们是否会成为lambda的一部分)。 属性。 看看是否有可能在Java中进行某种形式的全局类型推断也将很有趣。 但是所有这些东西都是另一天。
继续前进!
翻译自: https://www.javacodegeeks.com/2013/10/java-a-local-minimum-language-wise.html
java:8最小镜像