在Groovy

时间:2016-07-26 17:58:52

标签: java date reflection groovy introspection

我遇到一种情况,我会得到一个字符串,我需要确定Class<?>最适合它的值,给出以下约束:

  • 如果字符串是(忽略大小写)等于"true""false",则它是Boolean
  • 否则,如果String是一个没有小数点的整数,那么它是Integer
  • 否则,如果字符串是数字,则它是Double
  • 否则,如果字符串与日期时间格式YYYY-MM-DD hh:mm:ss.sss匹配,则其为Java Date
  • 这只是一个String afterall

我最好的尝试是讨厌的,涉及很多嵌套的try/catch块:

// Groovy pseudo-code
Class<?> determineValueType(String value) {
    Class<?> clazz
    if(value.equalsIgnoreCase('true') || value.equalsIgnoreCase('false')) {
        clazz = Boolean
    } else {
        try {
            Integer.parse(value)
            clazz = Integer
        } catch(Exception ex1) {
            try {
                Double.parse(value)
                clazz = Double
            } catch(Exception ex2) {
                try {
                    Date.parse('YYYY-MM-DD hh:mm:ss.sss', value)
                    clazz = Date
                } catch(Exception ex3) {
                    clazz = String
                }
            }
        }
    }

    clazz
}

是否有任何 Groovier 方法可以实现这一点,也许某些晦涩的Groovy反射API特有的东西?

2 个答案:

答案 0 :(得分:4)

有两种方法可以帮助您在Groovy的扩展String类(实际上在CharSequence上):

但是对于其他情况,AFAIK,您可以自己实现解析。您可以尝试使用地图和一些闭包来减少一些样板:

Class parse(val) {
    def convert = [
        (Integer) : { it.toInteger() },
        (Double)  : { it.toDouble() },
        (Date)    : { Date.parse('YYYY-MM-DD hh:mm:ss.sss', it) },
        (Boolean) : { Boolean.parseBoolean it },
        (String)  : { it }
    ]

    convert.findResult { key, value ->
        try {
            if (value(val)) return key
        } catch (e) {}
    }
}

assert parse('9.1') == Double
assert parse('9') == Integer
assert parse('1985-10-26 01:22:00.000') == Date // great scott!
assert parse('chicken') == String
assert parse('True') == Boolean

请注意,如果(Double)位于(Integer)之前,则测试将无效,因为9既是双精度又是整数。

答案 1 :(得分:3)

Groovy有一些功能可以让你使这个逻辑更加灵活。

  1. 强大的switch语句,支持正则表达式和闭包。
  2. Groovy JDK中的isIntegerisDouble内置CharSequence方法。可悲的是,没有严格的isBoolean因此我们需要自己实施。
  3. safe navigation operator以避免NPE。
  4. 结合这些功能......

    Class<?> determineValueType(String value) {
        switch (value) {
            case { ['true', 'false'].contains(value?.toLowerCase()) }: 
                return Boolean
            case { value?.isInteger() }: 
                return Integer
            case { value?.isDouble() }: 
                return Double
            case ~/^\d{4}-\d{2}-\d{2} \d{1,2}:\d{2}:\d{2}\.\d{3}$/: 
                return Date
            default: 
                return String
        }
    }
    
    assert determineValueType('true') == Boolean
    assert determineValueType('false') == Boolean
    assert determineValueType('2039230') == Integer
    assert determineValueType('203923.0') == Double
    assert determineValueType('2016-07-26 12:00:00.000') == Date
    assert determineValueType('foo') == String
    

    我使用正则表达式而不是SimpleDateFormat来避免必须捕获异常。它可能具有稍微不同的语义,但您也可以创建一个辅助方法,如果Date.parse抛出异常,则返回false。