জাভা 8 তুলনামূলক প্রকারের অনুক্রম দ্বারা খুব বিভ্রান্ত


84

আমি এর মধ্যে পার্থক্য দিকে তাকিয়ে করে থাকেন Collections.sortএবং list.sort, বিশেষ করে ব্যবহার সংক্রান্ত Comparatorস্ট্যাটিক পদ্ধতি এবং কিনা PARAM ধরনের ল্যামডা এক্সপ্রেশন প্রয়োজন হয়। আমরা শুরু করার আগে, আমি জানি যে আমি পদ্ধতি উল্লেখগুলি ব্যবহার করতে পারি, উদাহরণস্বরূপ Song::getTitleআমার সমস্যাগুলি কাটিয়ে উঠতে, তবে এখানে আমার ক্যোয়ারী তেমন কিছু নয় যা আমি ঠিক করতে চাই তবে এমন একটি উত্তর যার আমি উত্তর চাই, অর্থাৎ কেন জাভা সংকলক এটিকে এভাবে পরিচালনা করছেন? ।

এগুলি আমার সন্ধান ধরুন আমাদের ArrayListকয়েকটি ধরণের Songগান রয়েছে এবং এর সাথে 3 টি স্ট্যান্ডার্ড গেট পদ্ধতি রয়েছে:

    ArrayList<Song> playlist1 = new ArrayList<Song>();

    //add some new Song objects
    playlist.addSong( new Song("Only Girl (In The World)", 235, "Rhianna") );
    playlist.addSong( new Song("Thinking of Me", 206, "Olly Murs") );
    playlist.addSong( new Song("Raise Your Glass", 202,"P!nk") );

এখানে উভয় প্রকারের বাছাই পদ্ধতিতে কল রয়েছে যা কোনও সমস্যা নেই:

Collections.sort(playlist1, 
            Comparator.comparing(p1 -> p1.getTitle()));

playlist1.sort(
            Comparator.comparing(p1 -> p1.getTitle()));

আমি চেইন করতে শুরু করার thenComparingসাথে সাথে নিম্নলিখিতগুলি ঘটে:

Collections.sort(playlist1,
            Comparator.comparing(p1 -> p1.getTitle())
            .thenComparing(p1 -> p1.getDuration())
            .thenComparing(p1 -> p1.getArtist())
            );

playlist1.sort(
        Comparator.comparing(p1 -> p1.getTitle())
        .thenComparing(p1 -> p1.getDuration())
        .thenComparing(p1 -> p1.getArtist())
        );

অর্থাত্ সিনট্যাক্স ত্রুটি কারণ এটি p1আর প্রকারটি জানে না। সুতরাং এটি ঠিক করার জন্য আমি Songপ্রথম প্যারামিটারে (তুলনা করার) টাইপ যুক্ত করব :

Collections.sort(playlist1,
            Comparator.comparing((Song p1) -> p1.getTitle())
            .thenComparing(p1 -> p1.getDuration())
            .thenComparing(p1 -> p1.getArtist())
            );

playlist1.sort(
        Comparator.comparing((Song p1) -> p1.getTitle())
        .thenComparing(p1 -> p1.getDuration())
        .thenComparing(p1 -> p1.getArtist())
        );

এখন এখানে বিবেচনা অংশ আসে। পি laylist1.sort, অর্থাৎ তালিকার জন্য, নিম্নলিখিত thenComparingসংস্থাগুলির জন্য সমস্ত সংকলন ত্রুটি সমাধান করে। তবে Collections.sortএটির জন্য এটি প্রথমটির জন্য সমাধান করে তবে শেষটি নয়। আমি পরীক্ষামূলকভাবে আরও কয়েকটি অতিরিক্ত কল যুক্ত করেছি thenComparingএবং এটি সর্বদা সর্বশেষের জন্য একটি ত্রুটি দেখায়, যদি না আমি (Song p1)প্যারামিটারটির জন্য না রাখি ।

এখন আমি এটি তৈরি করে TreeSetএবং ব্যবহার করে আরও পরীক্ষা করে দেখেছি Objects.compare:

int x = Objects.compare(t1, t2, 
                Comparator.comparing((Song p1) -> p1.getTitle())
                .thenComparing(p1 -> p1.getDuration())
                .thenComparing(p1 -> p1.getArtist())
                );


    Set<Song> set = new TreeSet<Song>(
            Comparator.comparing((Song p1) -> p1.getTitle())
            .thenComparing(p1 -> p1.getDuration())
            .thenComparing(p1 -> p1.getArtist())
            );

একই জিনিসটি ঘটে যায়, এর জন্য TreeSet, কোনও সংকলন ত্রুটি নেই তবে Objects.compareশেষ কলটির জন্য thenComparingত্রুটি দেখানো হয়।

কেউ কি দয়া করে ব্যাখ্যা করতে পারেন যে এটি কেন ঘটছে এবং কেন (Song p1)কেবল তুলনামূলক পদ্ধতিটি thenComparingকল করার সময় (কোনও কল ছাড়াই ) কেন ব্যবহার করার প্রয়োজন নেই ।

একই বিষয়ে অন্য একটি ক্যোয়ারী হ'ল আমি যখন এটি করি TreeSet:

Set<Song> set = new TreeSet<Song>(
            Comparator.comparing(p1 -> p1.getTitle())
            .thenComparing(p1 -> p1.getDuration())
            .thenComparing(p1 -> p1.getArtist())
            );

অর্থাত্ Songতুলনা পদ্ধতি কলের জন্য প্রথম ল্যাম্বদা প্যারামিটার থেকে টাইপটি সরিয়ে ফেলুন , এটি তুলনার কলের অধীনে সিনট্যাক্স ত্রুটিগুলি দেখায় এবং thenComparingচূড়ান্ত কলটিতে নয় তবে প্রথমটি thenComparingযা ঘটছিল তার প্রায় বিপরীত! অন্যদিকে, অন্য 3 টি উদাহরণের জন্য অর্থাত্‍ সহ Objects.compare, List.sortএবং Collections.sortআমি যখন প্রথম Songপ্যারাম টাইপটি সরিয়ে ফেলি এটি সমস্ত কলগুলির জন্য সিনট্যাক্স ত্রুটিগুলি দেখায়।

অগ্রিম ধন্যবাদ.

এক্সিলিপ কেপলার এসআর 2-এ আমি যে ত্রুটিগুলি পেয়েছিলাম তার স্ক্রিনশট অন্তর্ভুক্ত করার জন্য সম্পাদিত, যা আমি এখন থেকে পেয়েছি তা হল এক্স্লিপ সুনির্দিষ্ট কারণ কমান্ড-লাইনে JDK8 জাভা সংকলক ব্যবহার করার পরে এটি ঠিক আছে iles

Eclipse এ বাছাই করা ত্রুটি


আপনি যদি আপনার সমস্ত পরীক্ষায় যে সংকলন ত্রুটি বার্তাগুলি পেয়েছেন সেগুলি আপনার প্রশ্নে অন্তর্ভুক্ত করে রাখলে এটি সহায়ক হবে।
ইরান

4
সত্যি কথা বলতে, আমি মনে করি কারও পক্ষে সোর্স কোডটি চালিয়ে কী কী সমস্যা রয়েছে তা দেখার পক্ষে সবচেয়ে সহজ হবে।
প্রশান্তি

প্রকার ও কি কি t1এবং t2Objects.compareউদাহরণ? আমি তাদের অনুমান করার চেষ্টা করছি, তবে কম্পাইলারের ধরণের অনুক্রমের চেয়ে আমার ধরণের অনুমিতি স্থাপন করা অক্ষম। :-)
স্টুয়ার্ট

4
এছাড়াও আপনি কোন সংকলক ব্যবহার করছেন?
স্টুয়ার্ট

4
আপনার এখানে দুটি পৃথক সমস্যা রয়েছে। উত্তরদাতাদের মধ্যে একটি নির্দেশ করে যে আপনি পদ্ধতি উল্লেখগুলি ব্যবহার করতে পারেন, যা আপনি বাছাই করেছেন। ল্যাম্বডাস যেমন "স্পষ্টত টাইপড" এবং "স্পষ্টভাবে টাইপ করা" স্বাদে আসে, তেমনি পদ্ধতির উল্লেখগুলি "নির্ভুল" (একটি ওভারলোড) এবং "নিখরচায়" (একাধিক ওভারলোড) স্বাদে আসে। হয় সঠিক পদ্ধতি রেফ বা একটি সুস্পষ্ট ল্যাম্বদা উপস্থিত না থাকলে অতিরিক্ত টাইপিং তথ্য সরবরাহ করতে ব্যবহার করা যেতে পারে। (সুস্পষ্ট ধরণের সাক্ষী এবং ক্যাসেটগুলিও ব্যবহার করা যেতে পারে তবে প্রায়শই বড় হাতুড়ি হয়))
ব্রায়ান গোয়েজ

উত্তর:


105

প্রথমে, আপনি যে সমস্ত উদাহরণ বলেছিলেন ত্রুটিগুলি রেফারেন্স বাস্তবায়নের সাথে জরিমানা সংকলন করে (জেডিকে ৮ এর জ্যাভাক) এগুলি ইন্টেলিজজেও দুর্দান্ত কাজ করে, সুতরাং এটির ত্রুটিগুলি যা আপনি দেখছেন তা এক্সিলিপ-নির্দিষ্ট।

আপনার অন্তর্নিহিত প্রশ্নটি মনে হচ্ছে: "যখন আমি শৃঙ্খলা শুরু করি তখন কেন এটি কাজ করা বন্ধ করে দেয়।" কারণটি হ'ল ল্যাম্বদা এক্সপ্রেশন এবং জেনেরিক পদ্ধতির অনুরোধগুলি পলি এক্সপ্রেশন (তাদের প্রসঙ্গটি প্রাসঙ্গিক-সংবেদনশীল) যখন তারা পদ্ধতি প্যারামিটার হিসাবে উপস্থিত হয়, যখন তারা পরিবর্তে মেথড রিসিভার এক্সপ্রেশন হিসাবে উপস্থিত হয়, তারা হয় না।

যখন তুমি বললে

Collections.sort(playlist1, comparing(p1 -> p1.getTitle()));

উভয় প্রকারের যুক্তি comparing()এবং আর্গুমেন্টের জন্য সমাধান করার জন্য পর্যাপ্ত তথ্য রয়েছে p1। এর comparing()স্বাক্ষর থেকে কলটি তার টার্গেট প্রকারটি পায় Collections.sort, সুতরাং এটি অবশ্যই জানা comparing()উচিত যে এটি অবশ্যই ফিরে আসতে হবে Comparator<Song>এবং তাই p1অবশ্যই এটি করা উচিত Song

তবে আপনি যখন শৃঙ্খলা শুরু করবেন:

Collections.sort(playlist1,
                 comparing(p1 -> p1.getTitle())
                     .thenComparing(p1 -> p1.getDuration())
                     .thenComparing(p1 -> p1.getArtist()));

এখন আমরা একটি সমস্যা পেয়েছি। আমরা জানি যে যৌগের এক্সপ্রেশনটির comparing(...).thenComparing(...)একটি টার্গেট ধরণের রয়েছে Comparator<Song>তবে চেইনের জন্য রিসিভার এক্সপ্রেশনটি comparing(p -> p.getTitle()), একটি জেনেরিক পদ্ধতি কল, এবং আমরা এর অন্যান্য আর্গুমেন্ট থেকে এর ধরণের পরামিতিগুলি অনুমান করতে পারি না, আমরা ভাগ্যের বাইরে থাকি kind । যেহেতু আমরা এই প্রকাশের প্রকারটি জানি না, তাই আমরা জানি না যে এর কোনও thenComparingপদ্ধতি ইত্যাদি রয়েছে,

এটি ঠিক করার বিভিন্ন উপায় রয়েছে, যার মধ্যে আরও বেশি প্রকারের তথ্য ইনজেকশন জড়িত যাতে চেইনের প্রাথমিক অবজেক্টটি সঠিকভাবে টাইপ করা যায়। তারা হ'ল কাঙ্ক্ষিত ও হ্রাসপ্রবণতা হ্রাস করার জন্য:

  • মত একটি সঠিক পদ্ধতির রেফারেন্স (কোনও ওভারলোড ছাড়াই নয়) ব্যবহার করুন Song::getTitle। এরপরে এই comparing()কলটির জন্য প্রকারের ভেরিয়েবলগুলি নির্ধারণ করতে যথেষ্ট প্রকারের তথ্য দেয় এবং অতএব এটিকে একটি প্রকার দিন এবং তারপরে শৃঙ্খলে অবিরত থাকুন।
  • একটি সুস্পষ্ট ল্যাম্বদা ব্যবহার করুন (যেমন আপনি আপনার উদাহরণে করেছিলেন)।
  • জন্য একটি টাইপ সাক্ষী প্রদান comparing()কল: Comparator.<Song, String>comparing(...)
  • কাস্টারের সাথে একটি সুস্পষ্ট লক্ষ্য প্রকার সরবরাহ করুন, এতে রিসিভার এক্সপ্রেশন কাস্ট করে Comparator<Song>

13
প্রকৃতপক্ষে ওপিকে উত্তর দেওয়ার জন্য +1 কেবল সংশোধন / সমাধান দেওয়ার চেয়ে "সংকলক এটি কেন অনুমান করতে পারে না"।
জোফ্রে

আপনার উত্তর ব্রায়ান জন্য আপনাকে ধন্যবাদ। যাইহোক, আমি এখনও কিছু জবাবদিহি পেয়েছি, কেন list.sort সংগ্রহের সাথে আলাদাভাবে আচরণ করে ortসোর্টটির ক্ষেত্রে, পূর্বেরটির কেবল প্যারামিটারের प्रकारটি ধারণ করার জন্য প্রথম ল্যাম্বডা প্রয়োজন হয়, তবে পরবর্তীটিরও শেষের প্রয়োজন হয়, যেমন আমার সাথে তুলনা করা থাকলে তারপরে 5 ততকালীন তুলনা কলগুলি আমাকে তুলনা করতে এবং শেষের সাথে তুলনা করতে হবে (গানের পি 1) করতে হবে। এছাড়াও আমার মূল পোস্টে আপনি ট্রিসেটের নীচের উদাহরণটি দেখতে পাবেন যেখানে আমি সমস্ত প্যারাম প্রকারগুলি মুছে ফেলেছি এবং তবুও কম্পিউটারের সাথে শেষ কলটি ঠিক আছে তবে অন্যগুলি ঠিক নেই - তাই এটি ভিন্নভাবে আচরণ করে।
প্রশান্তি

4
@ ব্যবহারকারী 803770০৩70০ আপনি কি এখনও গ্রহগ্রাহের সংকলক ব্যবহার করছেন? আমি যদি আপনার প্রশ্নটি সঠিকভাবে বুঝতে পারি তবে আমি এই আচরণটি দেখিনি। আপনি (ক) জেডিকে 8 এবং (খ) এর জাভ্যাক দিয়ে চেষ্টা করে দেখতে পারেন যদি এটি ব্যর্থ হয় তবে কোডটি পোস্ট করতে পারেন?
ব্রায়ান গয়েটজ

@ ব্রায়ানগোয়েজ এই পরামর্শের জন্য ধন্যবাদ। আমি জাভ্যাকটি ব্যবহার করে কমান্ড উইন্ডোতে সবেমাত্র এটি সঙ্কলন করেছি এবং আপনি যেমন বলেছিলেন তেমন এটি সংকলন করেছে। এটি একটি Eclipse ইস্যু বলে মনে হচ্ছে। আমি এখনও পর্যন্ত ক্লিপস লুনায় আপডেট হয়নি, যা জেডিকে 8 এর জন্য নির্মিত, তাই আশা করা যায় এটি এটি ঠিক করা যেতে পারে। Eclipse এ কী ঘটছে তা দেখানোর জন্য আমার কাছে আসলে একটি স্ক্রিনশট রয়েছে তবে কীভাবে এখানে পোস্ট করতে হয় তা জানি না।
শান্তি

4
আমার মনে হয় তুমি বোঝাতে চাইছ Comparator.<Song, String>comparing(...)
shmosel

23

সমস্যাটি টাইপ ইনফারেন্সিং। (Song s)প্রথম তুলনায় একটি যুক্ত না করে ইনপুটটির ধরণটি comparator.comparingজানেন না তাই এটি বস্তুর ডিফল্ট হয়।

আপনি এই সমস্যাটি 3 টির মধ্যে 1 টি সমাধান করতে পারেন:

  1. নতুন জাভা 8 পদ্ধতির রেফারেন্স সিনট্যাক্স ব্যবহার করুন

     Collections.sort(playlist,
                Comparator.comparing(Song::getTitle)
                .thenComparing(Song::getDuration)
                .thenComparing(Song::getArtist)
                );
    
  2. স্থানীয় তুলনায় প্রতিটি তুলনামূলক পদক্ষেপ টানুন

      Comparator<Song> byName = (s1, s2) -> s1.getArtist().compareTo(s2.getArtist());
    
      Comparator<Song> byDuration = (s1, s2) -> Integer.compare(s1.getDuration(), s2.getDuration());
    
        Collections.sort(playlist,
                byName
                .thenComparing(byDuration)
                );
    

    সম্পাদনা

  3. তুলনাকারীর দ্বারা ফেরত পাঠানো ধরণের জোর করা (নোট করুন আপনার ইনপুট প্রকার এবং তুলনা কী প্রকার উভয়ই প্রয়োজন)

    sort(
      Comparator.<Song, String>comparing((s) -> s.getTitle())
                .thenComparing(p1 -> p1.getDuration())
                .thenComparing(p1 -> p1.getArtist())
                );
    

আমি মনে করি "শেষ" thenComparingসিনট্যাক্স ত্রুটি আপনাকে বিভ্রান্ত করছে। এটি আসলে পুরো শৃঙ্খলে এক ধরণের সমস্যা, এটি কেবল সংকলকটি কেবল শৃঙ্খলের প্রান্তটিকে একটি বাক্যবিন্যাস ত্রুটি হিসাবে চিহ্নিত করে কারণ যখন আমার অনুমানের সাথে চূড়ান্ত ফেরতের ধরণটি মেলে না।

আমি নিশ্চিত না কেন কেন একই ধরণের ক্যাপচারের Listধরণটি Collectionকরা উচিত তবে তুলনামূলকভাবে না হওয়ার চেয়ে কেন আরও ভাল ইনফারেন্সিং কাজ করা হচ্ছে ।


ArrayListএটি Collectionsসমাধানের জন্য নয় তবে কেন এটি চেনে (চেইনে প্রথম কল দেওয়া একটি Songপ্যারামিটার রয়েছে)?
সোটিরিওস ডেলিমনোলিস

4
আপনার জবাবের জন্য আপনাকে ধন্যবাদ, তবে, আপনি যদি আমার পোস্টটি পড়েন তবে আপনি দেখতে পেয়েছেন আমি বলেছিলাম: "আমরা শুরু করার আগে, আমি জানি যে আমি আমার সমস্যাগুলি কাটিয়ে ওঠার জন্য পদ্ধতি রেফারেন্সগুলি ব্যবহার করতে পারি, উদাহরণস্বরূপ গান :: getTitle, তবে আমার প্রশ্নটি এখানে এতটা নয় is আমি কিছু ঠিক করতে চাই তবে এমন কিছুের আমি উত্তর চাই, যা জাভা সংকলক কেন এভাবে পরিচালনা করছে ling "
প্রশান্তি

আমি ল্যাম্বদা এক্সপ্রেশন ব্যবহার করার সময় সংকলক কেন সেভাবে আচরণ করছে সে সম্পর্কে একটি উত্তর চাই। এটি (s -> s.getArtist ()) এর তুলনা স্বীকার করে তবে তারপরে যখন আমি চেইন করি then তুলনা কল, যেমন তুলনা ((গানের গুলি) -> s.getArtist ()) তারপর এই সমস্যাটি স্থির করে এবং তালিকা.সোর্ট এবং ট্রিসেটের জন্য এটি অতিরিক্ত প্যারাম ধরণের যোগ না করেই আরও সমস্ত সংকলন ত্রুটিগুলি সমাধান করে, তবে, কালেকশন.সোর্ট এবং অবজেক্টস ডট কমের উদাহরণগুলি দেখুন তারপরে শেষের তুলনা করা এখনও ব্যর্থ হয়েছে
প্রশান্তি

1

এই সংকলন সময়ের ত্রুটিটি মোকাবেলার আর একটি উপায়:

আপনার প্রথম তুলনা ফাংশনের পরিবর্তনশীল স্পষ্টভাবে কাস্ট করুন এবং তারপরে ভাল good আমি org.bson. ডকুমেন্টস অবজেক্টের তালিকাটি বাছাই করেছি। নমুনা কোড দেখুন

Comparator<Document> comparator = Comparator.comparing((Document hist) -> (String) hist.get("orderLineStatus"), reverseOrder())
                       .thenComparing(hist -> (Date) hist.get("promisedShipDate"))
                       .thenComparing(hist -> (Date) hist.get("lastShipDate"));
list = list.stream().sorted(comparator).collect(Collectors.toList());

0

playlist1.sort(...) প্লেলিস্ট 1 এর ঘোষণা থেকে, যা তুলনামূলককে "ছড়িয়ে দেয়", টাইপ ভেরিয়েবল ইয়ের জন্য গানের সীমা তৈরি করে।

ইন Collections.sort(...), এর মতো কোনও সীমাবদ্ধ নেই, এবং প্রথম তুলকটির ধরণ থেকে অনুমিতি বাকী অনুমানের জন্য সংকলকটির পক্ষে যথেষ্ট নয়।

আমি মনে করি আপনি এ থেকে "সঠিক" আচরণ পেয়ে যাবেন Collections.<Song>sort(...)তবে এটি পরীক্ষা করার জন্য একটি জাভা 8 ইনস্টল করবেন না।


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