নিরাপদে জাভায় দীর্ঘ থেকে আন্তঃ castালাই


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
দুটি কোড পাথ। একটি হ'ল উত্তরাধিকারসূত্রে এবং ইনটসের প্রয়োজন needs এই লিগ্যাসির ডেটা সমস্ত ইনট্রে মাপসই করা উচিত, তবে যদি এই অনুমান লঙ্ঘিত হয় তবে আমি একটি ব্যতিক্রম ছুঁড়ে দিতে চাই। অন্যান্য কোড পাথ দীর্ঘতর ব্যবহার করবে এবং কাস্টের প্রয়োজন হবে না।
ব্রিগহাম

197
আমি ভালবাসি কীভাবে লোকেরা সবসময় প্রশ্ন করে যে আপনি কী করতে চান তা কেন করতে চান। যদি এই প্রশ্নগুলিতে প্রত্যেকে তাদের পুরো ব্যবহারের কেস ব্যাখ্যা করে থাকে তবে কেউ এগুলি পড়তে সক্ষম হবে না, তাদের উত্তর খুব কম দেওয়া হবে।
বিটি

24
বিটি - এই কারণে অনলাইনে কোনও প্রশ্ন জিজ্ঞাসা করা সত্যই আমি ঘৃণা করি। আপনি যদি সহায়তা করতে চান তবে তা দুর্দান্ত, তবে 20 টি প্রশ্ন খেলবেন না এবং তাদের ন্যায্যতা প্রমাণ করার জন্য জোর করবেন না।
ম্যাসন 240

59
বিটি এবং ম্যাসন ২৪০ এর সাথে এখানে অসম্মতি: প্রশ্নকারীর এমন অন্য একটি সমাধান দেখানো প্রায়শই মূল্যবান যা তারা ভাবেননি। কোড গন্ধ ফ্ল্যাগিং আপ একটি দরকারী পরিষেবা। 'আমি কৌতূহল করি কেন' থেকে 'তাদের' ন্যায্যতা প্রমাণ করতে বাধ্য করতে 'এই দীর্ঘ পথ way
টমি হার্বার্ট

13
এমন অনেকগুলি জিনিস রয়েছে যা আপনি দীর্ঘায়িতগুলি সহ করতে পারেন না index উদাহরণস্বরূপ একটি অ্যারে।
স্কট

উত্তর:


579

এটি করতে জাভা 8 এর সাথে একটি নতুন পদ্ধতি যুক্ত করা হয়েছে ।

import static java.lang.Math.toIntExact;

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

অতিরিক্ত ArithmeticExceptionপ্রবাহের ক্ষেত্রে একটি নিক্ষেপ করবে ।

দেখা: Math.toIntExact(long)

জাভা ৮-তে আরও বেশ কয়েকটি ওভারফ্লো নিরাপদ পদ্ধতি যুক্ত করা হয়েছে They এগুলি সঠিকভাবে শেষ হয় ।

উদাহরণ:

  • 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)) এর নিরাপদ সুবিধার পদ্ধতি নেই।
আলেকসান্দ্র ডাবিনস্কি

তবে Math.toIntExact()সাধারণ কাস্টের পরিবর্তে ব্যবহারের পার্থক্য কী int? বাস্তবায়ন Math.toIntExact()শুধু কাস্ট longকরার int
ইয়ামাশিরো

@ ইয়ামাসিরোআরিওন আসলে ট্যানএ্যাক্ট্যাক্ট প্রয়োগের ফলে প্রথমে পরীক্ষা করা হয়েছে যে কাস্টটি একটি ওভারফ্লোতে পৌঁছবে কিনা, সেই ক্ষেত্রে এটি একটি অ্যারিমেটিক এক্সেপশন নিক্ষেপ করে। যদি কাস্ট এটি নিরাপদ থাকে তবে লম্বা থেকে শেষ পর্যন্ত কাস্ট করে যা এটি ফিরে আসে। অন্য কথায়, আপনি যদি এমন একটি দীর্ঘ সংখ্যার কাস্ট করার চেষ্টা করেন যা ইন্ট হিসাবে উপস্থাপন করা যায় না (উদাহরণস্বরূপ 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))। এটি করার অন্যান্য উপায়গুলির চারপাশে আমার মাথা পেতে অসুবিধা হয়। করুণা জাভা নেই unless
টম হাটিন -

5
+1 টি। এটি " ব্যতিক্রমী অবস্থার জন্য ব্যতিক্রমগুলি ব্যবহার করা উচিত " নিয়মের আওতায় পড়ে ।
অ্যাডাম রোজেনফিল্ড

4
(একটি আধুনিক সাধারণ-উদ্দেশ্যমূলক ভাষায় এটি
হ'ল

7
@ টম: ব্যক্তিগত পছন্দ, আমার ধারণা - আমি যতটা সম্ভব নেতিবাচক থাকতে পছন্দ করি। যদি আমি দিকে তাকিয়ে আছি একটি "যদি" একটি শরীরের যা একটি ব্যতিক্রম ছোঁড়ার সঙ্গে, আমি শর্ত এটি ব্যতিক্রমী বানাতে দেখতে চাই - মত মান "নীচে শেষ বন্ধ" হচ্ছে int
জন স্কিটি

6
@ টম: সেক্ষেত্রে আমি নেতিবাচক অপসারণ করব, "যদি" শরীরের অভ্যন্তরে castালাই / ফিরতি রেখেছি এবং তারপরে একটি ব্যতিক্রম ছুঁড়ে ফেলি, যদি আপনি বুঝতে চান আমার অর্থ কি।
জন স্কিটি

132

গুগল পেয়ারা এর সাথে ints বর্গ, আপনার পদ্ধতি পরিবর্তন করা যাবে:

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)সরাসরি কল করুন just
ডিমো 414

8
পেয়ারাতেও রয়েছে Ints.saturatedCastযা ব্যতিক্রম ছোঁড়ার পরিবর্তে নিকটতম মান প্রদান করবে।
জেক ওয়ালশ

হ্যাঁ, বিদ্যমান এপিআইটিকে আমার ক্ষেত্রে হিসাবে ব্যবহার করা নিরাপদ, প্রকল্পটিতে ইতিমধ্যে গ্রন্থাগারটি: অবৈধ হলে ব্যতিক্রম করা: Ints.checkedCast (দীর্ঘ) এবং Ints.saturatedCast (দীর্ঘ) দীর্ঘ থেকে আন্তঃ রূপান্তর করার জন্য নিকটতম পেতে।
ওসিফাই করুন

29

বিগডিসিমাল সহ:

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

আমি এটি পছন্দ করি, কারও কি এই সমাধানের বিরুদ্ধে কিছু আছে?
রুই মার্কস

12
ওয়েল, এটি একটি বিগডিসিমাল বরাদ্দ এবং দূরে ফেলে দিচ্ছে কেবল কোনও ইউটিলিটি পদ্ধতি কী হওয়া উচিত তা পেতে, তাই হ্যাঁ, এটি সর্বোত্তম প্রক্রিয়া নয়।
রিখিং

@ সেক্ষেত্রে রাইকিংয়ের 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
ঠিক আছে, কেন ডিও এবং ডিএনএস উভয়ই নেই? টিবিএইচ, মাঝে মাঝে আমি চাই যে আমি কী ধরণের প্যাটার্ন / কোড ব্যবহার করেছি কিনা তা পরীক্ষা করার জন্য কীভাবে জিনিসগুলি (ডিএনটি) না করা যায় তার একটি তালিকা আমার কাছে ছিল। যাইহোক, আমি এই "উত্তর" মুছতে পারি।
Andreas

1
ভাল অ্যান্টি-প্যাটার্ন। যাইহোক এটি দুর্দান্ত হত যদি আপনি ব্যাখ্যা করে থাকেন যে দীর্ঘ মানটি যদি ইনট-অফ-রেঞ্জের হয় তবে কী ঘটে? আমার ধারণা এখানে একটি ক্লাসকাস্ট এক্সেকশন বা এরকম কিছু থাকবে?
পিটার উইপ্পারম্যান 6

2
@ পিটারউইপ্পারম্যান: আমি আরও কিছু তথ্য যুক্ত করেছি। আপনি কি তাদের বোধগম্য শ্রদ্ধা বিবেচনা করেন? যথেষ্ট ব্যাখ্যামূলক?
Andreas

7

আমি দাবি করি যে কোনও মান কাস্ট করাতে মান বদলেছে কিনা তা দেখার সুস্পষ্ট উপায়টি ফলাফলটি কাস্ট করা এবং পরীক্ষা করা উচিত। আমি তুলনা করার সময় অপ্রয়োজনীয় castালাই সরিয়ে ফেলব। আমি একটি বর্ণের পরিবর্তনশীল নামগুলি সম্পর্কেও খুব আগ্রহী নই (ব্যতিক্রম 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
গুগল পেয়ারা ইনটস :: চেককাস্টের সাম্প্রতিক সংস্করণগুলি এটি করে।
লেসিক্যালস্কোপ

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 পূর্ণসংখ্যায় কাস্ট করা হবে M এমএটিভ্যালু (অর্থাত -2 ^ 31) সুতরাং তথ্য হারিয়ে গেছে।
জন স্কিটি

@ জোন স্কিট: সম্ভবত আমি এবং ওপি একে অপরের সাথে কথা বলছি। (int) 0xFFFFFFFFএবং (long) 0xFFFFFFFFLবিভিন্ন মান রয়েছে, তবে তাদের উভয় একই "তথ্য" ধারণ করে, এবং এটি int থেকে মূল দীর্ঘ মান বের করা প্রায় তুচ্ছ।
জনতা

0xFFFFFFFF এর পরিবর্তে দীর্ঘটি -1 শুরু করতে পারলে আপনি কীভাবে প্রকৃত দীর্ঘ মানটি বের করতে পারবেন?
জন স্কিটি

দুঃখিত যদি আমি "পরিষ্কার না হয়ে থাকি। আমি বলছি যে দীর্ঘ এবং ইন্টি উভয় উভয় যদি একই 32 বিটের তথ্য ধারণ করে, এবং যদি 32 তম বিট সেট করা থাকে তবে অন্তর্গত মানটি দীর্ঘ মান থেকে পৃথক, তবে এটি দীর্ঘ মান পেতে সহজ।
ভিড়

@ মোব রেফারেন্সে এটি কী? ওপির কোডটি সঠিকভাবে জানায় যে দীর্ঘ মানগুলি> 2 {in 31 in ints এ কাস্ট করা যায় না
আংশিক মেঘলা

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()); 
        }
}

আমি ক্লায়েন্টের একটি পোষ্ট করছে এমন ক্ষেত্রে এবং সার্ভার ডিবি কেবলমাত্র পূর্ণসংখ্যার বুঝতে পারে যখন ক্লায়েন্টটির দীর্ঘকাল রয়েছে।


: আপনি উপর "বাস্তব দীর্ঘ" মান একটি NumberFormatException পাবেন Integer.valueOf(Long.MAX_VALUE.toString()); ফলাফল java.lang.NumberFormatException: For input string: "9223372036854775807" প্রায় কাছাকাছি আউট-অফ-বিন্যাস-ব্যতিক্রম obfuscates কারণ এটি এখন একই ভাবে একটি স্ট্রিং অক্ষর ধারণকারী চিকিত্সা করা হয় চিকিত্সা করা হয় যে।
আন্দ্রেয়াস

2
এটিও সঙ্কলন করে না কারণ আপনি সর্বদা কোনও মান ফেরত দেন না।
প্যাট্রিক এম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.