最近这几年,Java 的使用规模有了很大的增长。在这篇博文里,本文作者将和大家探讨现在 Java 还缺少的内容。
作者 | Axel Rauschmayer
译者 | 彼得
责编 | 屠敏
出品 | CSDN(ID:CSDNNews)
以下为译文:
注:
有关前两个问题的更多想法,请参阅语言设计部分(http://2ality.com/2019/01/future-js.html#language-design)。
数值
根据数值来比较对象
现在,Java 只是对元数据类型(比如,字符串)才使用数值进行比较。也就是对这些元数据类型,根据它们包含的内容进行比较:
> 'abc'=== 'abc'
true
在对象之间,是根据对象的引用进行比较的。即任何一个对象只能和它自己相同:
> {x: 1, y: 4} === {x: 1, y: 4}
false
如果我们能够创建可以通过数值进行比较的对象,这会将非常有帮助:
> #{x: 1, y: 4} === #{x: 1, y: 4}
true
另一个方法是引入一种新的类来表示(具体细节待定):
@[ValueType]
classPoint{
// ···
}
注:这种方法是通过修饰符来说明该类是基于数值来进行比较的类。该方法是根据这个建议草案提出的(https://github.com/littledan/proposal-reserved-decorator-like-syntax)。
将对象放入数据结构中
由于对象是按引用进行比较的,因此像下面这样将它们放入ECMA的数据结构(如Map)中是没有什么实际意义:
constm = newMap();
m. set({x: 1, y: 4}, 1);
m. set({x: 1, y: 4}, 2);
assert.equal(m.size, 2);
这个问题可以通过自定义值的类型来解决,也可以通过自定义Set元素和Map键值的管理方法来实现。例如:
大整数(BigInt)
Java 中的 Number 类型都是 64 位(双精度)的。对于整数来说,有53位来表示整数的数值还有1位的符号位来表示正负。也就是,只能精确表示53位以内的整数,对于超出53位的整数,没有办法精确区分它们:
> 2 ** 53
9007199254740992
> (2 ** 53) + 1 // can’t be represented
9007199254740992
> (2 ** 53) + 2
9007199254740994
在某些情况下,这是一个很大的限制。现在,有一个对于大整数(BigInt)的建议。根据该建议,整数的精度可以根据需要进行扩展:
> 2n ** 53n
9007199254740992n
> (2n ** 53n) + 1n
9007199254740993n
大整数(BigInt)也支持类型转换,这样就可以得到固定位数的整数:
constint64a = BigInt.asUintN( 64, 12345n);
constint64b = BigInt.asUintN( 64, 67890n);
constresult = BigInt.asUintN( 64, int64a * int64b);
十进制运算
基于 IEEE 754 的规范,Java 中的 Number 类型都是64位(双精度)的。因为这些数是以二进制来表示,所以在进行小数运算的时候,你不可避免地会遇到四舍五入的问题:
> 0 .1+ 0 .2
0 .30000000000000004
在科学计算和金融领域,这是一个比较突出的问题。现在,有一个正处在初始阶段的关于10进制数值的表示方法的提议。如果该提议获得通过,数值可能会以如下方式表示,请注意在小数后面的m用于表示十进制数值:
> 0 .1m+ 0 .2m
0 .3m
数值分类
现在,在 java 中,对数值进行分类是一件非常麻烦的事:
> typeofnull
'object'
> typeoffunction() {}
'function'
> typeof[]
'object'
对于上述的这些问题,可以通过创建特定的 Java 库来解决。以后,如果有时间,我自己会试着实现。
函数式编程
更多的表达式
和 C 语言风格类似的编程语言都对于表达式和程序语句做了明确的区分:
// Conditional expression
letstr1 = someBool ? 'yes': 'no';
// Conditional statement
letstr2;
if(someBool) {
str2 = 'yes';
} else{
str2 = 'no';
}
在函数式语言中,任何对象都是表达式。使用表达式将使你能在任何表达式的上下文中使用表达式:
letstr3 = do{
if(someBool) {
'yes'
} else{
'no'
}
};
以下的代码是一个更实际的例子。如果没有 do 的表达式,为了避免作用域内的变量 result,就需要立即调用 arrow 函数来实现:
constfunc = (() =>{
letresult; // cache
return()=>{
if(result === undefined) {
result = someComputation();
}
returnresult;
}
})();
有了 do 表达式,你的代码会更简洁:
constfunc = do{
letresult;
()=>{
if(result === undefined) {
result = someComputation();
}
returnresult;
};
};
匹配:析构 switch
在 Java 中,直接处理对象是件很容易的事。但是,它没有基于对象结构的切换方法。在建议中提供的事例如下:
constresource = awaitfetch(jsonService);
case(resource) {
when { status: 200, headers: { 'Content-Length': s}} -> {
console.log( `size is ${s}`);
}
when { status: 404} -> {
console.log( 'JSON not found');
}
when {status} if(status >= 400) -> {
thrownewRequestError(res);
}
}
如上可见,新的 case 语句在某些方面类似于 switch 语句,但使用析构函数来处理 case 命令。在使用嵌套数据结构时(例如在编译器中),这种功能都很有用。模式匹配方案现在处于第一阶段。
管道(Pipeline)操作
对于管道(pipeline)操作,有两个互相竞争的提案。现在,我们先看一下"智能管道"提案;另外一个提案是"F# 管道"。
管道(pipeline)操作的基本思想可以用下面的递归调用来说明:
consty = h(g(f(x)));
但是,管道的概念没有反映出来我们思考的逻辑顺序。我们可以把我们对于上面公式的思考逻辑归纳为下面几步:
使用管道操作,可以使我们更好地描述我们的思考逻辑:
consty = x |> f |> g |> h;
换而言之,下面两个表达式是一样的:
f(123)
123 |> f
另外,管道操作还支持部分应用的功能。该功能类似于 .bind()函 数,下面两个表达式是一样的:
123|> f( #)
123|> (x => f(x))
管道操作的一个重要优势在于你可以像使用方法一样使用函数,而不用进行类型转换:
import{ map} from 'array-tools';
constresult = arr |> map(#, x => x * 2);
我们拿一个稍微长一点的例子来总结一下。这个例子来自于提议草案并稍作改动:
promise
|> await#
|> # || throw new TypeError(
`Invalid valuefrom${promise}`)
|> capitalize // function call
|> # + '!'
|> newUser.Message( #)
|> awaitstream.write( #)
|> console.log // method call
;
并发
Java 对于并发的支持一直比较有限。进程并发事实上的标准是 Worker API,它在 Web 浏览器和 node.js 中可用(在 v11.7 及更高版本中没有标志)。
在 Node.js 中,对于 Worker API 可以像下面这样使用:
const{
Worker, isMainThread, parentPort, workerData
} = require( 'worker_threads');
if(isMainThread) {
constworker = newWorker(__filename, {
workerData: 'the-data.json'
});
worker.on( 'message', result => console.log(result));
worker.on( 'error', err => console.error(err));
worker.on( 'exit', code => {
if(code !== 0) {
console.error( 'ERROR: '+ code);
}
});
} else{
const{readFileSync} = require( 'fs');
constfileName = workerData;
consttext = readFileSync(fileName, { encoding: 'utf8'});
constjson = JSON.parse(text);
parentPort.postMessage(json);
}
相对来讲,Worker 的方式是比较重量级的实现。每一种都需要有自己的领域(全局变量等)。我希望在将来能看到一个更量级的实现。
标准库
现在,Java 明显落后于其他语言的一个方面是它的标准库支持。最小的标准库支持确实有合理的一面,因为它们依赖的外部库会很快地发展和变化。但是,还是有一些非常有用的核心功能需要实现。
用模块替代命名空间(namespace)对象
Java 的标准库是在它支持模块之前创建的。因此,很多方法是被放在命名空间对象(例如 Object,Reflect,Math和JSON)中的:
如果能把这些方法放到特定的模块中,那就更好了。必须通过特殊的 URL 才能使用它们。比如可以使用 std 前缀:
// Old:
assert.deepEqual(
Object.keys({a: 1, b: 2}),
[ 'a', 'b']);
// New:
import{keys} from 'std:object';
assert.deepEqual(
keys({a: 1, b: 2}),
[ 'a', 'b']);
使用这种方法的好处是:
支持 iterables(同步和异步)的工具函数(Helper)
iterables 能提供很多便利,包括只有在需要的时候才计算数值和支持许多数据源。但是,目前 Java 对 iterables 提供的工具函数却很少。比如,现在如果你要筛选、映射或减少 iterable,则只能将它转换为数组:
constiterable = newSet([ -1, 0, -2, 3]);
constfilteredArray = [...iterable].filter( x=>x >= 0);
assert.deepEqual(filteredArray, [ 0, 3]);
如果 Java 能有对 iterables 支持的工具函数,你就可以直接过滤 iterables:
constfilteredIterable = filter(iterable, x => x >= 0);
assert.deepEqual(
// We only convert the iterable to an Array, so we can
// check what’s in it:
[...filteredIterable], [ 0, 3]);
下面是更多可能的 iterables 工具函数的示例:
// Count elements in an iterable
assert.equal(count(iterable), 4);
// Create an iterable over a part of an existing iterable
assert.deepEqual(
[ ...slice(iterable, 2)],
[ -1, 0]);
// Number the elements of an iterable
// (producing another – possibly infinite – iterable)
for( const[i,x] of zip(range(0), iterable)) {
console.log(i, x);
}
// Output:
// 0, -1
// 1, 0
// 2, -2
// 3, 3
请注意:
不可改变的数据
希望 Java 最好能对非破坏性数据转换提供更多支持。两个相关的库是:
对于日期和时间的更好支持
Java 内置的对日期和时间的支持有许多奇怪的地方。也正因为如此,才建议大家在最基本的任务之外的其他任务中才使用系统的日期和时间库。
值得庆幸的是,现在人们正在研究日期和时间方面的更好的 API:
constdateTime = newCivilDateTime( 2000, 12, 31, 23, 59);
constinstantInChicago = dateTime.withZone( 'America/Chicago');
可能不太需要的功能
可选链接(chaining)的优缺点
当前一个比较普遍的提议是对于可选链接的支持。根据该提议,以下两个表达式是等效的:
obj?.prop
(obj === undefined|| obj === null) ? undefined: obj.prop
这一功能尤其适用于属性链:
obj? .foo? .bar? .baz
但是,这个功能也有缺点:
可选链接的一个替代方案是在某个特定的位置提取一次信息:
无论采用以上哪种方法,您都能进行检查。早一点发现存在的问题。
更多资料:
我们需要运算符重载吗?
现在,有些人正在为运算符重载做前期的准备工作,但我觉得中缀函数应用程序可能已经足够了(尽管目前没有针对它的提议):
import{BigDecimal, plus} from 'big-decimal';
constbd1 = newBigDecimal( '0.1');
constbd2 = newBigDecimal( '0.2');
constbd3 = bd1 @plusbd2; // plus(bd1, bd2)
中缀函数应用的好处是:
这是嵌套表达式的一个例子:
a @plus b @minus c @ timesd
times(minus(plus(a, b), c), d)
有趣的是,pipeline 操作符也有助于提高代码的可读性:
plus(a, b)
|> minus( #, c)
|> times( #, d)
其他内容
这些是我偶尔会错过的一些事情,我也不认为它们像我之前提到的内容那样重要:
newChainedError(msg, origError)
re `/^${RE_YEAR}-${RE_MONTH}-${RE_DAY}$/u`
> constre = newRegExp( RegExp.escape( ':-)'), 'ug');
> ':-) :-) :-)'.replace(re, '
相关下载
原标题:手滑了?冯绍峰被曝否认出轨后取关赵丽颖,名字显示关注列表前端 10日有网友爆料一名刚结婚没多久的男星在女方怀孕期间出轨,而爆料中“fsf”“赵详情>>
QQ设置始终保持在其他窗口前端呢?那么,请看下面的教程。攻略对象电脑1台 教程1份步骤分解1下载安装软件【QQ】,如下图所示;2选中软件,右键单击,选择【打开】,如下图所示;3输入登陆账详情>>
大家都知道,pot player是和kmpplayer齐名的公认的最好的播放软件之一,它以其强大的播放功能被人们所称赞。但是由于功能太多,所以很多时候不如其他播放器方便。但是一旦上手,其详情>>
页面的加载速度直接关联着用户的体验。研究表明,用户最满意的打开网页时间是2-5秒,如果等待超过10秒,99%的用户会关闭这个网页。那么如何优化网页的加载速度呢,下面将从几个方面讲解。1.减少详情>>
【什么是web应用】1、什么是webweb本意是蜘蛛网和网的意思,在互联网中是需要用浏览器浏览的网页2、什么是web应用web应用就是应用在web上的应用,就是b/s架构模式【b/s,c/s模式应用详情>>
作为程序员经常会有一些口头禅,比如说“代码复用思想”,“写高质量的代码”,“代码在精不在多”,“思路比努力更重要”,这些话中大多强调的是策略的重要性,在工作中,勤奋固然重要,如果能在勤奋的基础上强调详情>>
作为初入职场的我们,在学习与工作中,总是会遇到不同的挫折。虽然有些错误与某一个具体的行为相关,但有些错误却是所有Web开发人员都需要面对的挑战。因此,通过研究,体验和观察,千锋武汉Web培训小编总结详情>>
之所以写这个总结,还要从上周的一次移动端项目的debug说起。那天,测试小姐姐拿着自己的iphone6s过来找我,说页面打不开。我想:这怎么可能,我手机里挺好的呀,Chrome调试工具也没报详情>>
8月10日,由ITValue和钛媒体集团联合举办的2018IT价值峰会在海南三亚成功举行。本次大会围绕“复盘、重构”的主题,回顾了过去10年科技、商业环境的变化。过去10年里,随着云计算、大数据、人详情>>
SpreadJS是一款基于HTML5的纯Java电子表格和网格功能控件,在外观、功能和操作上都与Excel高度类似,在表格数据处理上比Grid类控件更为优秀,被开发人员誉为“可嵌入详情>>
随着现在来前端的又是时间,前端的世界已经开始进入了下一个阶段,传统的网页制作已经逐渐被现在的状态解决了,传统的网页制作中耗时成本长,前期的切图已经逐渐跟不上现在的发展速度。但是随着现在技术的发展,许详情>>
今天小编给想学前端的同学们讲一下怎样入门前端。小编虽然不是专业的程序员,但是前端也算及格,写一些页面完全能应。小编的前端是自学的,在学习的过程中,我的感受就是:网上有很多视频,有免费的也有付费的,但详情>>
小编推荐:Fundebug专注于Java、微信小程序、微信小游戏,Node.js和Java实时BUG监控。真的是一个很好用的bug监控费服务,众多大佬公司都在使用。译者按:简要介绍五大前端框架特详情>>
gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器;它不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成;使用它,我们不仅可以很愉快的编写代码,而且详情>>
Web前端在最近几年的发展令人瞩目,成为最近炙手可热的岗位。随着人才需求的增加,企业给Web前端开发工程师开出的薪资也是持续上扬。这种盛况自然而然就引发了众多朋友进入这个行业。想要涉足该领域,好的技详情>>
小编为您搜罗的答案:应该有吧详情>>
1.前端开发是怎样的?1.1前端开发是什么?【起源】:Web前端开发是从【网页制作】演变而来的。在互联网的演化进程中,网页制作是Web1.0时代的产物,那时网站的主要内容都是静态的,使详情>>
1.前端开发是怎样的?1.1前端开发是什么?【起源】:Web前端开发是从【网页制作】演变而来的。在互联网的演化进程中,网页制作是Web1.0时代的产物,那时网站的主要内容都是静态的,使详情>>
Web前端应用十种常用技术,随着JS与XHTML的应用普及,越来越多的web界面应用技术出现在网站上,比如我们常见的日历控件,搜索下拉框等,这些web界面应用技术大大的详情>>
前端射击人物角色特点全面介绍,我们在游戏中随着收集的齿轮逐渐的变多,那么我们就能够不断地解锁更多的人物,每一种人物都有着他们独特的作用和能力,玩家利用好这些,我们就能够在过关的道路上变详情>>
前端射击攻略高分通关技巧讲解,玩家在游戏中我们要不断的躲避各种障碍物,收集齿轮来提升我们的实力,游戏中关卡的障碍物还是非常的多的,玩家想要能够成功跨越坚持更久获得高分,还是比较困难的,详情>>