जावा में सुरक्षित रूप से लंबे समय तक कास्टिंग


488

यह सत्यापित करने के लिए जावा में सबसे मुहावरेदार तरीका क्या longहैint किसी भी जानकारी को खोना नहीं करता?

यह मेरा वर्तमान कार्यान्वयन है:

public static int safeLongToInt(long l) {
    int i = (int)l;
    if ((long)i != l) {
        throw new IllegalArgumentException(l + " cannot be cast to int without changing its value.");
    }
    return i;
}

34
दो कोड पथ। एक विरासत है और किलों की जरूरत है। उस विरासत डेटा को सभी एक इंट में फिट करते हैं, लेकिन मैं एक अपवाद फेंकना चाहता हूं अगर उस धारणा का उल्लंघन होता है। अन्य कोड पथ का उपयोग करेगा और कलाकारों की आवश्यकता नहीं होगी।
ब्रिघम

197
मुझे प्यार है कि लोग हमेशा सवाल करते हैं कि आप वह क्यों करना चाहते हैं जो आप करना चाहते हैं। अगर हर कोई इन सवालों में अपने पूर्ण उपयोग के मामले की व्याख्या करता है, तो कोई भी उन्हें पढ़ने में सक्षम नहीं होगा, बहुत कम उन्हें जवाब देता है।
बीटी

24
बीटी - मैं वास्तव में इस कारण से ऑनलाइन कोई भी प्रश्न पूछने से नफरत करता हूं। यदि आप मदद करना चाहते हैं, तो यह बहुत अच्छा है, लेकिन 20 सवाल न करें और उन्हें खुद को सही ठहराने के लिए मजबूर करें।
मेसन 240

59
बीटी और मेसन 240 से असहमत यहां: प्रश्नकर्ता को एक और समाधान दिखाने के लिए अक्सर मूल्यवान है जो उन्होंने सोचा नहीं है। कोड की महक को फहराना एक उपयोगी सेवा है। यह 'मैं उत्सुक हूँ क्यों ...' से 'उन्हें खुद को सही ठहराने के लिए मजबूर करने' का एक लंबा रास्ता है।
टॉमी हर्बर्ट

13
ऐसी बहुत सी चीजें हैं जिन्हें आप लोंगों के साथ नहीं कर सकते हैं।
स्कॉट

जवाबों:


579

ऐसा करने के लिए जावा 8 के साथ एक नया तरीका जोड़ा गया है।

import static java.lang.Math.toIntExact;

long foo = 10L;
int bar = toIntExact(foo);

फेंक देंगे ArithmeticExceptionअतिप्रवाह के मामले में ।

देख: Math.toIntExact(long)

कई अन्य अतिप्रवाह सुरक्षित तरीके जावा 8 में जोड़े गए हैं। वे सटीक रूप से समाप्त होते हैं

उदाहरण:

  • Math.incrementExact(long)
  • Math.subtractExact(long, long)
  • Math.decrementExact(long)
  • Math.negateExact(long),
  • Math.subtractExact(int, int)

5
हम यह भी है addExactऔर multiplyExact। ध्यान दें कि विभाजन ( MIN_VALUE/-1) और निरपेक्ष मूल्य ( abs(MIN_VALUE)) में सुरक्षित सुविधा विधियाँ नहीं हैं।
Aleksandr Dubinsky

लेकिन Math.toIntExact()सामान्य कलाकारों के बजाय उपयोग करने में क्या अंतर है int? के कार्यान्वयन Math.toIntExact()सिर्फ डाले longकरने के लिए int
यमशिरो रियान

@YamashiroRion वास्तव में कार्यान्वयन ofIntExact पहले जाँच करता है कि क्या कास्ट एक अतिप्रवाह की ओर ले जाएगा, जिस स्थिति में यह एक अंकगणित अपवाद को फेंकता है। केवल अगर यह कास्ट सुरक्षित है, तो लंबे समय से इंट में डाली जाती है, जिस पर वह वापस लौटता है। दूसरे शब्दों में, यदि आप एक लंबी संख्या डालने की कोशिश करते हैं जिसे इंट के रूप में प्रस्तुत नहीं किया जा सकता है (जैसे किसी भी संख्या को सख्ती से 2 147 483 647 से ऊपर) तो यह एक अंकगणित को फेंक देगा। यदि आप एक साधारण कास्ट के साथ भी ऐसा ही करते हैं, तो आपका परिणामी इंट वैल्यू गलत होगा।
पियरे-एंटोनी

306

मुझे लगता है कि मैं इसे बस के रूप में करूँगा:

public static int safeLongToInt(long l) {
    if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
        throw new IllegalArgumentException
            (l + " cannot be cast to int without changing its value.");
    }
    return (int) l;
}

मुझे लगता है कि दोहराया कास्टिंग की तुलना में इरादे को अधिक स्पष्ट रूप से व्यक्त करता है ... लेकिन यह कुछ व्यक्तिपरक है।

संभावित ब्याज का नोट - सी # में यह सिर्फ होगा:

return checked ((int) l);

7
मैं हमेशा रेंज की जाँच करता हूँ (!(Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE))। मुझे ऐसा करने के अन्य तरीकों के आसपास अपना सिर प्राप्त करना मुश्किल लगता है। Pity Java में नहीं है unless
टॉम हॉल्टिन -

5
+1। यह "अपवादों को असाधारण स्थितियों के लिए उपयोग किया जाना चाहिए " नियम के तहत आता है ।
एडम रोसेनफील्ड

4
(एक आधुनिक सामान्य-प्रयोजन की भाषा में यह होगा: "एह! लेकिन इन्टल्स का मनमाना आकार है?")
टॉम हॉल्टिन -

7
@ टॉम: व्यक्तिगत पसंद, मुझे लगता है - मैं संभव के रूप में कुछ नकारात्मक है पसंद करते हैं। अगर मैं एक "if" देख रहा हूं, तो एक शरीर के साथ, जो एक अपवाद को फेंकता है, मैं ऐसी परिस्थितियां देखना चाहता हूं जो इसे असाधारण दिखती हैं - जैसे कि मूल्य "नीचे के अंत से दूर" हो रहा है int
जॉन स्कीट

6
@Tom: उस स्थिति में मैं नेगेटिव को हटा देता हूं, "अगर" बॉडी के अंदर कास्ट / रिटर्न डाल देता हूं, और फिर बाद में एक अपवाद फेंक देता हूं, अगर आप देखते हैं कि मेरा क्या मतलब है।
जॉन स्कीट

132

Google अमरूद की इन्टस क्लास के साथ, आपके तरीके को निम्न में बदला जा सकता है:

public static int safeLongToInt(long l) {
    return Ints.checkedCast(l);
}

लिंक किए गए डॉक्स से:

checkedCast

public static int checkedCast(long value)

valueयदि संभव हो तो इसके बराबर मान लौटाता है।

पैरामीटर: value - intप्रकार की सीमा में कोई भी मूल्य

रिटर्न: वह intमूल्य जो बराबर होता हैvalue

फेंकता है: IllegalArgumentException - यदि valueइससे अधिक Integer.MAX_VALUEया उससे कम हैInteger.MIN_VALUE

संयोग से, आपको safeLongToIntरैपर की आवश्यकता नहीं है , जब तक कि आप इसे पाठ्यक्रम के व्यापक रिफैक्टरिंग के बिना कार्यक्षमता को बदलने के लिए नहीं छोड़ना चाहते हैं।


3
अमरूद Ints.checkedCastठीक वैसा ही करता है जैसा कि ओपी करता है, संयोग से
आंशिक रूप से बादल छाए रहेंगे

14
अमरूद के घोल के लिए +1, हालांकि इसे किसी दूसरी विधि में लपेटने की कोई वास्तविक आवश्यकता नहीं है, बस Ints.checkedCast(l)सीधे कॉल करें ।
dimo414

8
अमरूद भी Ints.saturatedCastएक अपवाद फेंकने के बजाय निकटतम मान लौटाएगा।
जेक वॉल्श

हां, मेरे मामले के रूप में मौजूदा एपीआई का उपयोग करना सुरक्षित है, परियोजना में पहले से ही पुस्तकालय: अमान्य होने पर अपवाद को फेंकने के लिए: Ints.checkedCast (लंबी) और Ints.saturatedCast (लंबे) को लंबे समय तक अंतर करने के लिए निकटतम पाने के लिए।
ऑसिफाइ करें

29

BigDecimal के साथ:

long aLong = ...;
int anInt = new BigDecimal(aLong).intValueExact(); // throws ArithmeticException
                                                   // if outside bounds

मुझे यह पसंद है, किसी को भी इस समाधान के खिलाफ कुछ है?
रुई मार्केज़

12
खैर, यह एक BigDecimal को आवंटित करने और दूर फेंकने के लिए है जो एक उपयोगिता विधि होनी चाहिए, इसलिए हाँ, यह सबसे अच्छी प्रक्रिया नहीं है।
रेकिंग

@ इस संबंध में, इसका उपयोग करना बेहतर है BigDecimal.valueOf(aLong), इसके बजाय new BigDecimal(aLong), यह निरूपित करने के लिए कि नए उदाहरण की आवश्यकता नहीं है। क्या निष्पादन पर्यावरण उस पद्धति पर कैशिंग करता है, क्या यह विशिष्ट है, जैसे एस्केप एनालिसिस की संभावित उपस्थिति। अधिकांश वास्तविक जीवन के मामलों में, इसका प्रदर्शन पर कोई प्रभाव नहीं पड़ता है।
होल्गर

17

यहाँ एक समाधान है, यदि आप मूल्य के बारे में परवाह नहीं करते हैं तो यह बड़ा है; आवश्यक है;)

public static int safeLongToInt(long l) {
    return (int) Math.max(Math.min(Integer.MAX_VALUE, l), Integer.MIN_VALUE);
}

लगता है, आप गलत हैं ... यह अच्छा काम करेगा तो नकारात्मक। भी, क्या मतलब है too low? कृपया, उपयोग-मामला प्रदान करें।
विटाली कुलिकोव

यह समाधान तेजी से एक और सुरक्षित एक है, तो हम परिणाम का पालन करने के लिए लॉन्ग टू इंट कास्ट करने के लिए बात कर रहे हैं।
विटाली कुलिकोव

11

डॉन: यह एक समाधान नहीं है!

मेरा पहला दृष्टिकोण था:

public int longToInt(long theLongOne) {
  return Long.valueOf(theLongOne).intValue();
}

लेकिन यह सिर्फ एक इंट को लंबे समय तक कास्ट करता है, संभावित रूप से नए Longउदाहरण बनाता है या उन्हें लॉन्ग पूल से पुनर्प्राप्त करता है।


कमियां

  1. Long.valueOfLongयदि संख्या Longपूल की सीमा [-128, 127] के भीतर नहीं है तो एक नया उदाहरण बनाता है ।

  2. intValueकार्यान्वयन की तुलना में ज्यादा कुछ नहीं करता है:

    return (int)value;

तो यह सिर्फ कास्टिंग longकरने से भी बदतर माना जा सकता है int


4
मदद करने के आपके प्रयास की सराहना की जाती है, लेकिन काम नहीं करने वाली किसी चीज़ का उदाहरण देते हुए समाधान प्रदान करने के समान नहीं है जो काम करता है। यदि आप एक सही तरीका जोड़ने के लिए संपादित करेंगे, तो यह बहुत अच्छा हो सकता है; अन्यथा, उत्तर के रूप में पोस्ट किया जाना वास्तव में उपयुक्त नहीं है।
पोप

4
ठीक है, क्यों नहीं दोनों और क्या नहीं है? Tbh, कभी-कभी मेरी इच्छा है कि मेरे पास इस बात की एक सूची थी कि मैं इस तरह के पैटर्न / कोड का उपयोग करने के लिए चीजों (DONT) को कैसे नहीं करूं। वैसे भी, मैं इस "उत्तर" को हटा सकता हूं।
एंड्रियास

1
अच्छा विरोधी पैटर्न। वैसे भी यह बहुत अच्छा होता यदि आप यह समझाते कि यदि लंबे समय तक मूल्य सीमा से बाहर हो तो क्या होता है? मुझे लगता है कि वहाँ एक ClassCastException या ऐसा कुछ होगा?
पीटर विप्रमैन

2
@PeterWippermann: मैंने कुछ और जानकारी जोड़ी है। क्या आप उन्हें सम्मानजनक समझते हैं। व्याख्यात्मक पर्याप्त?
एंड्रियास

7

मैं दावा करता हूं कि यह देखने का स्पष्ट तरीका है कि क्या मूल्य में परिवर्तन से मूल्य बदल जाएगा और परिणाम की जांच होगी। हालांकि, मैं तुलना करते समय अनावश्यक कलाकारों को हटा दूंगा। मैं एक अक्षर के चर नामों (अपवाद xऔर y, लेकिन नहीं, जब उनका मतलब पंक्ति और स्तंभ (कभी-कभी क्रमशः)) से बहुत अधिक उत्सुक नहीं हूँ ।

public static int intValue(long value) {
    int valueInt = (int)value;
    if (valueInt != value) {
        throw new IllegalArgumentException(
            "The long value "+value+" is not within range of the int type"
        );
    }
    return valueInt;
}

हालांकि, वास्तव में मैं इस रूपांतरण से बचना चाहता हूं यदि संभव हो तो। जाहिर है कभी-कभी यह संभव नहीं है, लेकिन उन मामलों IllegalArgumentExceptionमें लगभग निश्चित रूप से गलत अपवाद है जहां तक ​​ग्राहक कोड का संबंध है।


1
Google Guava Ints :: checkCast do के हाल के संस्करणों में यह है।
lexicalscope

2

जावा पूर्णांक प्रकारों को हस्ताक्षरित के रूप में दर्शाया गया है। 2 31 और 2 32 (या -2 31 और -2 32 ) के बीच इनपुट के साथ कलाकार सफल होंगे लेकिन आपका परीक्षण विफल हो जाएगा।

क्या जांचना है कि क्या सभी उच्च बिट्स के longसभी समान हैं:

public static final long LONG_HIGH_BITS = 0xFFFFFFFF80000000L;
public static int safeLongToInt(long l) {
    if ((l & LONG_HIGH_BITS) == 0 || (l & LONG_HIGH_BITS) == LONG_HIGH_BITS) {
        return (int) l;
    } else {
        throw new IllegalArgumentException("...");
    }
}

3
मैं नहीं देखता कि इसके साथ क्या सांकेतिकता है। आपको एक उदाहरण है जो दे सकता है नहीं है खो जानकारी लेकिन करता है परीक्षण असफल? 2 ^ 31 को Integer.MIN_VALUE (यानी -2 ^ 31) को कास्ट किया जाएगा ताकि जानकारी खो गई हो।
जॉन स्कीट

@ जोंन स्कीट: शायद मैं और ओपी एक दूसरे से बात कर रहे हैं। (int) 0xFFFFFFFFऔर (long) 0xFFFFFFFFLअलग-अलग मूल्य हैं, लेकिन उन दोनों में समान "जानकारी" है, और यह मूल से लंबे समय तक मूल्य निकालने के लिए लगभग तुच्छ है।
भीड़

आप मूल लॉन्ग वैल्यू को इंट से कैसे निकाल सकते हैं, जब 0xFFFFFFFF के बजाय लॉन्ग -1 के साथ शुरू हो सकता है?
जॉन स्कीट

क्षमा करें यदि मैं स्पष्ट नहीं हूँ। मैं कह रहा हूँ कि यदि लंबे और int दोनों में एक ही 32 बिट्स की जानकारी है, और यदि 32 बिट सेट है, तो इंट वैल्यू लंबे मूल्य से अलग है, लेकिन यह है कि लंबा मूल्य प्राप्त करना आसान है।
भीड़ दें

@ एमओबी इस संदर्भ में क्या है? OP का कोड सही रूप से रिपोर्ट करता है कि लंबे मान> 2 ^ {31} को किलों में नहीं डाला जा सकता है
आंशिक रूप से बादल छाए रहेंगे

0
(int) (longType + 0)

लेकिन लोंग अधिकतम से अधिक नहीं हो सकते :)


1
+ 0यदि जावा तार करने के लिए एक समान तरीके से सांख्यिक प्रकार संयोजन इलाज किया, यह काम हो सकता है, इस रूपांतरण के लिए कुछ नहीं कहते हैं लेकिन जब से यह नहीं अपने किसी कारण के लिए एक ऐड कार्रवाई करते है।
छः

-7

एक अन्य समाधान हो सकता है:

public int longToInt(Long longVariable)
{
    try { 
            return Integer.valueOf(longVariable.toString()); 
        } catch(IllegalArgumentException e) { 
               Log.e(e.printstackstrace()); 
        }
}

मैंने उन मामलों के लिए यह कोशिश की है जहां ग्राहक एक POST कर रहा है और सर्वर DB केवल इंटीजर को समझता है जबकि ग्राहक के पास एक लंबा है।


आपको "वास्तविक लंबे" मानों पर एक नंबरफ़ॉर्मएक्स अपवाद मिलेगा: इसमें Integer.valueOf(Long.MAX_VALUE.toString()); परिणाम java.lang.NumberFormatException: For input string: "9223372036854775807"बहुत अधिक आउट-ऑफ-रेंज-अपवाद को मानते हैं क्योंकि यह अब उसी तरह से व्यवहार किया जाता है जैसे कि स्ट्रिंग युक्त अक्षरों का इलाज किया जाता है।
एंड्रियास

2
यह भी संकलित नहीं करता है क्योंकि आप हमेशा एक मूल्य वापस नहीं करते हैं।
पैट्रिक एम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.