搜索
首页Javajava教程Java和Ceylon对象的构造和验证的代码案例分享

当变换Java代码为Ceylon代码时,有时候我会遇到一些Java类构造器混淆了验证与初始化的情形。让我们使用一个简单但是人为的代码例子来说明我想阐述的意思。

一些坏代码

考虑下面的Java类。(伙计,不要在家里写这样的代码)

public class Period {
    private final Date startDate;
    private final Date endDate;
    //returns null if the given String
    //does not represent a valid Date
    private Date parseDate(String date) {
       ...
    }
    public Period(String start, String end) {
        startDate = parseDate(start);
        endDate = parseDate(end);
    }
    public boolean isValid() {
        return startDate!=null && endDate!=null;
    }
    public Date getStartDate() {
        if (startDate==null) 
            throw new IllegalStateException();
        return startDate;
    }
    public Date getEndDate() {
        if (endDate==null)
            throw new IllegalStateException();
        return endDate;
    }
}

嘿,我之前已经警告过,它是人为的。但是,在实际Java代码中找个像这样的东西实际上并非不常见。

这里的问题在于,即使输入参数(在隐藏的parseDate()方法中)的验证失败了,我们还是会获得一个Period的实例。但是我们获取的那个Period不是一个“有效的”状态。严格地说,我的意思是什么呢?

好吧,假如一个对象不能有意义地响应公用操作时,我会说它处于一个非有效状态。在这个例子里,getStartDate() 和getEndDate()会抛出一个IllegalStateException异常,这就是我认为不是“有意义的”一种情况。

从另外一方面来看这个例子,在设计Period时,我们这儿出现了类型安全的失败。未检查的异常代表了类型系统中的一个“漏洞”。因此,一个更好的Period的类型安全的设计,会是一个不使用未检查的异常—在这个例子中意味着不抛出IllegalStateException异常。

(实际上,在真实代码中,我更有可能遇到一个getStartDate() 方法它不检查null ,在这个代码行之后就会导致一个NullPointerException异常,这就更加糟糕了。)

我们能够很容易地转换上面的Period类成为Ceylon形式的类:

shared class Period(String start, String end) {
    //returns null if the given String
    //does not represent a valid Date
    Date? parseDate(String date) => ... ;
    value maybeStartDate = parseDate(start);
    value maybeEndDate = parseDate(end);
    shared Boolean valid
        => maybeStartDate exists 
        && maybeEndDate exists;
    shared Date startDate {
        assert (exists maybeStartDate);
        return maybeStartDate;
    }
    shared Date endDate {
        assert (exists maybeEndDate);
        return maybeEndDate;
    }
}

当然了,这段代码也会遇到与原始Java代码同样的问题。两个assert符号冲着我们大喊,在代码的类型安全中有一个问题。

使Java代码变得更好

Java里我们怎么改进这段代码呢?好吧,这儿就是一个例子关于Java饱受诟病的已检查异常会是一个非常合理的解决方法!我们可以稍微修改下Period来从它的构造器中抛出一个已检查的异常:

public class Period {
    private final Date startDate;
    private final Date endDate;
    //throws if the given String
    //does not represent a valid Date
    private Date parseDate(String date)
            throws DateFormatException {
       ...
    }
    public Period(String start, String end) 
            throws DateFormatException {
        startDate = parseDate(start);
        endDate = parseDate(end);
    }
    public Date getStartDate() {
        return startDate;
    }
    public Date getEndDate() {
        return endDate;
    }
}

现在,使用这个解决方案,我们就不会获取一个处于非有效状态的Period,实例化Period的代码会由编译器负责去处理无效输入的情形,它会捕获一个DateFormatException异常。

try {
    Period p = new Period(start, end);
    ...
}
catch (DateFormatException dfe) {
    ...
}

这是一个对已检查异常不错的、完美的、正确的使用,不幸的是我几乎很少看到Java代码像上面这样使用已检查异常。

使Ceylon代码变得更好

那么Ceylon怎么样呢?Ceylon没有已检查异常,因而我们需要寻找一个不同的解决方式。典型地,在Java调用一个函数会抛出一个已检查异常的情形中,Ceylon会调用函数返回一个联合类型。因为,一个类的初始化不返回除了类自己外的任何类型,我们需要提取一些混合的初始化/验证的逻辑来使其成为一个工厂函数。

//returns DateFormatError if the given 
//String does not represent a valid Date
Date|DateFormatError parseDate(String date) => ... ;
shared Period|DateFormatError parsePeriod
        (String start, String end) {
    value startDate = parseDate(start);
    if (is DateFormatError startDate) {
        return startDate;
    }
    value endDate = parseDate(end);
    if (is DateFormatError endDate)  {
        return endDate;
    }
    return Period(startDate, endDate);
}
shared class Period(startDate, endDate) {
    shared Date startDate;
    shared Date endDate;
}

根据类型系统,调用者有义务去处理DateFormatError:

value p = parsePeriod(start, end);
if (is DateFormatError p) {
    ...
}
else {
    ...
}

或者,如果我们不关心给定日期格式的实际问题(这是有可能的,假定我们工作的初始化代码丢失了那个信息),我们可以使用Null而不是DateFormatError:

//returns null if the given String 
//does not represent a valid Date
Date? parseDate(String date) => ... ;
shared Period? parsePeriod(String start, String end)
    => if (exists startDate = parseDate(start), 
           exists endDate = parseDate(end))
       then Period(startDate, endDate)
       else null;
shared class Period(startDate, endDate) {
    shared Date startDate;
    shared Date endDate;
}

至少可以说,使用工厂函数的方法是优秀的,因为通常来说在验证逻辑和对象初始化之间它具有更好的隔离。这点在Ceylon中特别有用,在Ceylon中,编译器在对象初始化逻辑中添加了一些非常严厉的限制,以保证对象的所有领域仅被赋值一次。

以上是Java和Ceylon对象的构造和验证的代码案例分享的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JVM性能与其他语言JVM性能与其他语言May 14, 2025 am 12:16 AM

JVM'SperformanceIsCompetitiveWithOtherRuntimes,operingabalanceOfspeed,安全性和生产性。1)JVMUSESJITCOMPILATIONFORDYNAMICOPTIMIZAIZATIONS.2)c提供NativePernativePerformanceButlanceButlactsjvm'ssafetyFeatures.3)

Java平台独立性:使用示例Java平台独立性:使用示例May 14, 2025 am 12:14 AM

JavaachievesPlatFormIndependencEthroughTheJavavIrtualMachine(JVM),允许CodeTorunonAnyPlatFormWithAjvm.1)codeisscompiledIntobytecode,notmachine-specificodificcode.2)bytecodeisisteredbytheybytheybytheybythejvm,enablingcross-platerssectectectectectross-eenablingcrossectectectectectection.2)

JVM架构:深入研究Java虚拟机JVM架构:深入研究Java虚拟机May 14, 2025 am 12:12 AM

TheJVMisanabstractcomputingmachinecrucialforrunningJavaprogramsduetoitsplatform-independentarchitecture.Itincludes:1)ClassLoaderforloadingclasses,2)RuntimeDataAreafordatastorage,3)ExecutionEnginewithInterpreter,JITCompiler,andGarbageCollectorforbytec

JVM:JVM与操作系统有关吗?JVM:JVM与操作系统有关吗?May 14, 2025 am 12:11 AM

JVMhasacloserelationshipwiththeOSasittranslatesJavabytecodeintomachine-specificinstructions,managesmemory,andhandlesgarbagecollection.ThisrelationshipallowsJavatorunonvariousOSenvironments,butitalsopresentschallengeslikedifferentJVMbehaviorsandOS-spe

Java:写一次,在任何地方跑步(WORA) - 深入了解平台独立性Java:写一次,在任何地方跑步(WORA) - 深入了解平台独立性May 14, 2025 am 12:05 AM

Java实现“一次编写,到处运行”通过编译成字节码并在Java虚拟机(JVM)上运行。1)编写Java代码并编译成字节码。2)字节码在任何安装了JVM的平台上运行。3)使用Java原生接口(JNI)处理平台特定功能。尽管存在挑战,如JVM一致性和平台特定库的使用,但WORA大大提高了开发效率和部署灵活性。

Java平台独立性:与不同的操作系统的兼容性Java平台独立性:与不同的操作系统的兼容性May 13, 2025 am 12:11 AM

JavaachievesPlatFormIndependencethroughTheJavavIrtualMachine(JVM),允许Codetorunondifferentoperatingsystemsswithoutmodification.thejvmcompilesjavacodeintoplatform-interploplatform-interpectentbybyteentbytybyteentbybytecode,whatittheninternterninterpretsandectectececutesoneonthepecificos,atrafficteyos,Afferctinginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginging

什么功能使Java仍然强大什么功能使Java仍然强大May 13, 2025 am 12:05 AM

JavaispoperfulduetoitsplatFormitiondence,对象与偏见,RichstandardLibrary,PerformanceCapabilities和StrongsecurityFeatures.1)Platform-dimplighandependectionceallowsenceallowsenceallowsenceallowsencationSapplicationStornanyDevicesupportingJava.2)

顶级Java功能:开发人员的综合指南顶级Java功能:开发人员的综合指南May 13, 2025 am 12:04 AM

Java的顶级功能包括:1)面向对象编程,支持多态性,提升代码的灵活性和可维护性;2)异常处理机制,通过try-catch-finally块提高代码的鲁棒性;3)垃圾回收,简化内存管理;4)泛型,增强类型安全性;5)ambda表达式和函数式编程,使代码更简洁和表达性强;6)丰富的标准库,提供优化过的数据结构和算法。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具