2016-09-09 8 views
0

Я немного смущен, используя значение double.Использование путаницы с двойным значением, когда groovy решает сделать значение в double vs BigDecimal?

Когда я, как показано ниже: -

double foo = 20.46455 
assert 20 == foo.round() 
assert 20.46 == foo.round(2) 

Это работает отлично. но когда я что-то вроде как: -

def foo = 20.46455 
assert 20 == foo.round() 

он бросает: -

java.lang.NullPointerException

и

def foo = 20.46455 
assert 20.46 == foo.round(2) 

он бросает: -

groovy.lang.MissingMethodException: Нет сигнатуры метода: java.math.BigDecimal.round() применим для типов аргументов: (java.lang.Integer) значения: [2] Возможные решения: round (java.math .MathContext), найти(), пау (INT), мощность (java.lang.Integer), найти (groovy.lang.Closure) и (java.lang.Number)

Это означает, что по умолчанию в groovy, стоимость сохранения в BigDecimal и BigDecimal.round() ожидаем java.math.MathContext как ввод.

Но моя путаница начинается, когда я использую Math.round(), который кроме double в качестве входных данных, то почему ниже заявления является получение передается в то время как заводной сохранить по умолчанию в BigDecimal?

def foo = 20.46455 
assert 20 == Math.round(foo) 

И почему я должен использовать .toDouble() пройти мой тест, в то время как foo имеет значение в формате double как ниже?

def foo = 20.46455 
assert 20 == foo.toDouble().round() 
assert 20.46 == foo.toDouble().round(2) 

Примечание: - Я не хочу знать, как round двойное значение, я просто хочу знать, почему groovy ведет себя по-разному в каждом случае ??

+0

@yash Я не хочу округлять число. Я просто хочу знать, почему 'groovy' ведет себя по-разному в каждом случае. Спасибо .. :) –

+0

@NathanHughes На самом деле я знаю, как обойти 'BigDecimal' или' Double'..И да, вы правы, мой вопрос: 'когда groovy решает сделать что-то двойное против BigDecimal?' –

+0

У меня также есть название вопроса, спасибо .. :) –

ответ

2

Groovy автоматически и неявно использует BigDecimal для любых чисел с плавающей запятой, если вы не определяете тип или не добавляете суффикс для числа (например, D).

Примеры:

def foo = 20.46455 
println foo.getClass() 

Выходные:

класс java.math.BigDecimal

double foo = 20.45645 
println foo.getClass() 

Выход:

класс java.lang.Double

def foo = 20.45645d 
println foo.getClass() 

Выход:

класс java.lang.Double

Тип преобразование:

Groovy также имеет определенные преобразования автоматического типа, и это является причиной, почему даже если Math.round() принимает только double и float примитивов в качестве параметров, то код не терпит неудачу, когда вы передаете BigDecimal. Чтобы доказать это, вы могли бы реализовать свою собственную round функцию и проверить, что происходит с преобразованиями типа:

Примеры:

def round(double foo) { 
    println foo.getClass() 
    return foo.round() 
} 

def foo = 20.46455 
println foo.getClass() 
assert 20 == round(foo) 

Выход:

класс java.math. BigDecimal

класс java.lang.Double

Некоторые более действительные примеры неявных преобразований:

def round(float foo) { 
    println foo.getClass() 
    return foo.round() 
} 

def foo = 20.46455 
println foo.getClass() 
assert 20 == round(foo) 

Выход:

класс java.math.BigDecimal

класс java.lang.Float

def round(float foo) { 
    println foo.getClass() 
    return foo.round() 
} 

def foo = 20 
println foo.getClass() 
assert 20 == round(foo) 

Выход:

класс java.lang.Integer

класс java.lang.Float

def round(double foo) { 
    println foo.getClass() 
    return foo.round() 
} 

def foo = 20 
println foo.getClass() 
assert 20 == round(foo) 

Выход:

класс java.lang.Integer

класс java.lang.Двойной

def round(BigDecimal foo) { 
    println foo.getClass() 
    return foo 
} 

double foo = 20.0 
println foo.getClass() 
assert 20 == round(foo) 

Выход:

класс java.lang.Double

класс java.lang.BigDecimal

Как правило, если число основано на плавающей запятой (double, float, BigDecimal) произойдет неявное преобразование типов между собой, и код будет генерировать исключение при попытке конвертировать в номера с неплавающей точкой (например, int или long). Если число не является типом с плавающей точкой (int, long), оно может быть преобразовано между типами неплавающих и плавающих точек, поскольку числа с плавающей запятой также включают в себя неплавающие точки в качестве подмножества (например, 1 может быть представлено с 1.0) , Это имеет смысл, так как вы не можете передавать информацию с плавающей запятой из float в int (20.5 не может быть представлено переменной int), но в большинстве случаев вы можете сделать обратное, причем случайное исключение переполнения для большие значения (например, действительно большое число long в переменной float).

+0

Тогда почему это ['def foo = 20.46455; assert 20 == Math.round (foo)'] (https://docs.oracle.com/javase/7/docs /api/java/lang/Math.html#round(double)) пройти? –

+0

'def foo = 20.46455' позволяет Groovy решить, какой тип этой переменной имеет использование вывода типа, и он выбирает BigDecimal. 'double foo = 20.46455' заставляет переменную быть типом' double'. Вы могли бы использовать суффикс для принудительного объявления 'double', как этот' def foo = 20.46455D' –

+0

Но он передается без принуждения к 'double', поэтому я запутался, я использую только' double foo = 20.46455' и groovy автоматически воспринимает его как 'double', когда использует его как' assert 20 == Math.round (foo) ', но когда я использовал его как' foo.round() 'groovy принимает его как' BigDecimal', и он бросает исключение ... –