Chuyển đổi BigDecimal thành Integer


134

Tôi có phương thức Hibernate trả về cho tôi một BigDecimal. Tôi có một phương thức API khác mà tôi cần để vượt qua số đó nhưng nó chấp nhận Integer làm tham số. Tôi không thể thay đổi kiểu trả về hoặc kiểu biến của cả hai phương thức.

Bây giờ làm thế nào để chuyển đổi BigDecimal thành Integer và chuyển nó sang phương thức thứ hai?

Có cách nào thoát khỏi điều này?


6
Tôi đã sửa tiêu đề của bạn. Đây là chuyển đổi, không đúc.
Hầu tước Lorne

Câu trả lời:


209

Bạn sẽ gọi myBigDecimal.intValueExact()(hoặc chỉ intValue()) và nó thậm chí sẽ ném ngoại lệ nếu bạn mất thông tin. Điều đó trả về một int nhưng autoboxing sẽ chăm sóc điều đó.


1
intValueExact()là một khuyến nghị tốt; nó đã được thêm vào trong 1.5
Anon

Gọi điện intValue()là nguy hiểm trừ khi bạn đặt cược 100% cuộc sống của mình vào số dương rằng số đó nằm trong Integerphạm vi.
Snekse 14/03/2015

1
Điều này có hợp lý không: "Integer.valueOf (myBigDecimal.intValueExact ())"?
OddDev

32

Bạn có thể đảm bảo rằng BigDecimalsẽ không bao giờ chứa một giá trị lớn hơn Integer.MAX_VALUE?

Nếu có, thì đây là mã của bạn gọi intValue:

Integer.valueOf(bdValue.intValue())

Đúng. Tôi đoán nó sẽ không chứa giá trị lớn hơn Integer.MAX_VALUE
Vishal

2
Không có lý do gì để làm valueOf ngoài việc lấy Object thay vì nguyên thủy phải không?
Basil

Tôi sẽ nói đây nên là câu trả lời chính thức vì a. đề cập đến các giới hạn, b. ngăn chặn hộp thư tự động.
ledlogic

22

TL; DR

Sử dụng một trong số này cho các nhu cầu chuyển đổi phổ quát

//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8    
bigDecimal.toBigInteger().intValueExact()

Lý luận

Câu trả lời phụ thuộc vào yêu cầu là gì và cách bạn trả lời những câu hỏi này.

  • Liệu BigDecimalcó khả năng sẽ có một phần phân số khác không?
  • Liệu BigDecimalcó khả năng không phù hợp với Integerphạm vi?
  • Bạn có muốn các phần phân số khác không được làm tròn hoặc cắt ngắn?
  • Làm thế nào bạn muốn phần không phân số tròn?

Nếu bạn trả lời không cho 2 câu hỏi đầu tiên, bạn chỉ có thể sử dụng BigDecimal.intValueExact()như những người khác đã đề xuất và để nó nổ tung khi có điều gì đó bất ngờ xảy ra.

Nếu bạn không hoàn toàn 100% tự tin về câu hỏi số 2, sau đó intValue()luôn luôn là câu trả lời sai.

Làm cho nó tốt hơn

Hãy sử dụng các giả định sau dựa trên các câu trả lời khác.

  • Chúng tôi ổn với việc mất độ chính xác và cắt giảm giá trị bởi vì đó là những gì intValueExact()và quyền anh tự động làm
  • Chúng tôi muốn có một ngoại lệ được ném khi phạm vi BigDecimallớn hơn Integerphạm vi bởi vì mọi thứ khác sẽ trở nên điên rồ trừ khi bạn có nhu cầu rất cụ thể về sự bao bọc xảy ra khi bạn thả các bit thứ tự cao.

Với các thông số đó, intValueExact()sẽ đưa ra một ngoại lệ khi chúng ta không muốn nó nếu phần phân số của chúng ta khác không. Mặt khác, intValue()đừng ném ngoại lệ khi nó BigDecimalquá lớn nếu chúng ta quá lớn.

Để có được điều tốt nhất của cả hai thế giới, hãy làm tròn BigDecimalđầu tiên, sau đó chuyển đổi. Điều này cũng có lợi ích là cho bạn quyền kiểm soát nhiều hơn trong quá trình làm tròn.

Kiểm tra Groovy Spock

void 'test BigDecimal rounding'() {
    given:
    BigDecimal decimal = new BigDecimal(Integer.MAX_VALUE - 1.99)
    BigDecimal hugeDecimal = new BigDecimal(Integer.MAX_VALUE + 1.99)
    BigDecimal reallyHuge = new BigDecimal("10000000000000000000000000000000000000000000000")
    String decimalAsBigIntString = decimal.toBigInteger().toString()
    String hugeDecimalAsBigIntString = hugeDecimal.toBigInteger().toString()
    String reallyHugeAsBigIntString = reallyHuge.toBigInteger().toString()

    expect: 'decimals that can be truncated within Integer range to do so without exception'
    //GOOD: Truncates without exception
    '' + decimal.intValue() == decimalAsBigIntString
    //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information
    // decimal.intValueExact() == decimalAsBigIntString
    //GOOD: Truncates without exception
    '' + decimal.setScale(0, RoundingMode.DOWN).intValueExact() == decimalAsBigIntString

    and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception'
    //BAD: hugeDecimal.intValue() is -2147483648 instead of 2147483648
    //'' + hugeDecimal.intValue() == hugeDecimalAsBigIntString
    //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information
    //'' + hugeDecimal.intValueExact() == hugeDecimalAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + hugeDecimal.setScale(0, RoundingMode.DOWN).intValueExact() == hugeDecimalAsBigIntString

    and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception'
    //BAD: hugeDecimal.intValue() is 0
    //'' + reallyHuge.intValue() == reallyHugeAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + reallyHuge.intValueExact() == reallyHugeAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + reallyHuge.setScale(0, RoundingMode.DOWN).intValueExact() == reallyHugeAsBigIntString

    and: 'if using Java 8, BigInteger has intValueExact() just like BigDecimal'
    //decimal.toBigInteger().intValueExact() == decimal.setScale(0, RoundingMode.DOWN).intValueExact()
}

18

Vâng, bạn có thể gọi BigDecimal.intValue():

Chuyển đổi BigDecimal này thành int. Chuyển đổi này tương tự như chuyển đổi nguyên thủy thu hẹp từ gấp đôi thành ngắn như được định nghĩa trong Đặc tả ngôn ngữ Java: mọi phần phân đoạn của BigDecimal này sẽ bị loại bỏ và nếu "BigInteger" kết quả là quá lớn để phù hợp với int, chỉ có mức thấp -order 32 bit được trả lại. Lưu ý rằng chuyển đổi này có thể mất thông tin về cường độ và độ chính xác tổng thể của giá trị BigDecimal này cũng như trả về kết quả với dấu ngược lại.

Sau đó, bạn có thể gọi một cách rõ ràng Integer.valueOf(int)hoặc để tự động đấm bốc làm điều đó cho bạn nếu bạn đang sử dụng một phiên bản Java đủ gần đây.


9

Sau đây nên làm thủ thuật:

BigDecimal d = new BigDecimal(10);
int i = d.intValue();



-4

Tôi thấy rằng những điều trên không làm việc cho tôi. Tôi đã lấy một giá trị ô từ JTable nhưng không thể tăng gấp đôi hoặc int, vv Giải pháp của tôi:

Object obj = getTable().getValueAt(row, 0);

trong đó hàng 0 sẽ luôn là một số. Hy vọng điều này sẽ giúp bất cứ ai vẫn cuộn!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.