CodeGym /جاوا بلاگ /Random-UR /جاوا کا موازنہ کرنے والا انٹرفیس
John Squirrels
سطح
San Francisco

جاوا کا موازنہ کرنے والا انٹرفیس

گروپ میں شائع ہوا۔
جاوا میں موازنہ اور موازنہ کے بارے میں لکھنے والے صرف سست لوگ نہیں ہیں۔ میں سست نہیں ہوں، لہذا براہ کرم ایک اور وضاحت کے بارے میں پیار اور گرفت کریں۔ مجھے امید ہے کہ یہ ضرورت سے زیادہ نہیں ہوگا۔ اور ہاں، یہ مضمون اس سوال کا جواب ہے: " کیا آپ میموری سے کمپیریٹر لکھ سکتے ہیں؟ " مجھے امید ہے کہ ہر کوئی اس مضمون کو پڑھنے کے بعد میموری سے موازنہ لکھنے کے قابل ہو جائے گا۔ Javas Comparator انٹرفیس - 1

تعارف

جیسا کہ آپ جانتے ہیں، جاوا ایک آبجیکٹ پر مبنی زبان ہے۔ نتیجے کے طور پر، جاوا میں اشیاء کو ہیرا پھیری کرنے کا رواج ہے۔ لیکن جلد یا بدیر، آپ کو کسی خاصیت کی بنیاد پر اشیاء کا موازنہ کرنے کے کام کا سامنا کرنا پڑتا ہے۔ مثال کے طور پر : فرض کریں کہ ہمارے پاس کلاس کے ذریعہ بیان کردہ کچھ پیغام ہے Message:
public static class Message {
    private String message;
    private int id;

    public Message(String message) {
        this.message = message;
        this.id = new Random().nextInt(1000);
    }
    public String getMessage() {
        return message;
    }
    public Integer getId() {
        return id;
    }
    public String toString() {
        return "[" + id + "] " + message;
    }
}
اس کلاس کو ٹیوٹوریل پوائنٹ جاوا کمپائلر میں رکھیں ۔ درآمدی بیانات بھی شامل کرنا نہ بھولیں:
import java.util.Random;
import java.util.ArrayList;
import java.util.List;
طریقہ کار میں main، کئی پیغامات بنائیں:
public static void main(String[] args){
    List<Message> messages = new ArrayList();
    messages.add(new Message("Hello, World!"));
    messages.add(new Message("Hello, Sun!"));
    System.out.println(messages);
}
آئیے سوچتے ہیں کہ اگر ہم ان کا موازنہ کرنا چاہیں تو کیا کریں گے؟ مثال کے طور پر، ہم شناخت کے لحاظ سے ترتیب دینا چاہتے ہیں۔ اور ترتیب بنانے کے لیے، ہمیں کسی نہ کسی طرح اشیاء کا موازنہ کرنے کی ضرورت ہے تاکہ یہ سمجھ سکیں کہ کون سی چیز پہلے آنی چاہیے (یعنی چھوٹی) اور کس کی پیروی کرنی چاہیے (یعنی بڑی)۔ آئیے java.lang.Object جیسی کلاس سے شروعات کریں ۔ ہم جانتے ہیں کہ تمام طبقے واضح طور پر Objectکلاس کے وارث ہیں۔ اور یہ سمجھ میں آتا ہے کیونکہ یہ اس تصور کی عکاسی کرتا ہے کہ "ہر چیز ایک چیز ہے" اور تمام طبقات کے لیے مشترکہ رویہ فراہم کرتی ہے۔ یہ کلاس حکم دیتی ہے کہ ہر کلاس کے دو طریقے ہیں: → hashCode طریقہ آبجیکٹ کی hashCodeکچھ عددی ( ) نمائندگی دیتا ہے ۔ intاس کا کیا مطلب ہے؟ اس کا مطلب یہ ہے کہ اگر آپ کلاس کی دو مختلف مثالیں بناتے ہیں، تو ان میں مختلف hashCodes ہونا چاہیے۔ طریقہ کار کی وضاحت اتنا ہی کہتی ہے: "جتنا معقول حد تک عملی ہے، کلاس آبجیکٹ کے ذریعہ بیان کردہ ہیش کوڈ کا طریقہ الگ الگ اشیاء کے لیے الگ الگ عدد واپس کرتا ہے"۔ دوسرے الفاظ میں، دو مختلف s کے لیے ، مختلف s instanceہونا چاہیے ۔ hashCodeیعنی یہ طریقہ ہمارے مقابلے کے لیے موزوں نہیں ہے۔ → equals_ طریقہ equalsسوال کا جواب دیتا ہے "کیا یہ اشیاء برابر ہیں؟" اور واپس کرتا ہے a boolean." پہلے سے طے شدہ طور پر، اس طریقہ میں درج ذیل کوڈ ہوتا ہے:
public boolean equals(Object obj) {
    return (this == obj);
}
یعنی، اگر یہ طریقہ اوور رائڈ نہیں ہے، تو یہ بنیادی طور پر کہتا ہے کہ آیا آبجیکٹ کے حوالہ جات مماثل ہیں یا نہیں۔ یہ وہ نہیں ہے جو ہم اپنے پیغامات کے لیے چاہتے ہیں، کیونکہ ہمیں میسج آئی ڈیز میں دلچسپی ہے، آبجیکٹ ریفرینسز میں نہیں۔ اور یہاں تک کہ اگر ہم equalsطریقہ کو اوور رائیڈ کرتے ہیں، تو ہم سب سے زیادہ امید کر سکتے ہیں یہ سیکھنا ہے کہ آیا وہ برابر ہیں۔ اور یہ ہمارے لیے آرڈر کا تعین کرنے کے لیے کافی نہیں ہے۔ تو پھر ہمیں کیا چاہیے؟ ہمیں کسی ایسی چیز کی ضرورت ہے جو موازنہ کرے۔ جو موازنہ کرتا ہے وہ ہے Comparator۔ Java API کھولیں اور Comparator تلاش کریں ۔ java.util.Comparatorدرحقیقت، ایک انٹرفیس ہے java.util.Comparator and java.util.Comparable جیسا کہ آپ دیکھ سکتے ہیں، ایسا انٹرفیس موجود ہے۔ ایک طبقہ جو اسے نافذ کرتا ہے کہتا ہے، "میں ایک ایسا طریقہ نافذ کرتا ہوں جو اشیاء کا موازنہ کرتا ہوں۔" صرف ایک چیز جو آپ کو واقعی یاد رکھنے کی ضرورت ہے وہ ہے موازنہ کنٹریکٹ، جس کا اظہار مندرجہ ذیل ہے:

Comparator returns an int according to the following rules: 
  • It returns a negative int if the first object is smaller
  • It returns a positive int if the first object is larger
  • It returns zero if the objects are equal
اب ایک کمپیریٹر لکھتے ہیں۔ ہمیں درآمد کرنے کی ضرورت ہوگی java.util.Comparator۔ درآمدی بیان کے بعد، mainطریقہ میں درج ذیل کو شامل کریں: Comparator<Message> comparator = new Comparator<Message>(); یقیناً، یہ کام نہیں کرے گا، کیونکہ Comparatorایک انٹرفیس ہے۔ لہٰذا ہم {}قوسین کے بعد گھوبگھرالی منحنی خطوط وحدانی جوڑتے ہیں۔ منحنی خطوط وحدانی کے اندر درج ذیل طریقہ لکھیں:
public int compare(Message o1, Message o2) {
    return o1.getId().compareTo(o2.getId());
}
آپ کو ہجے یاد کرنے کی بھی ضرورت نہیں ہے۔ موازنہ کرنے والا وہ ہوتا ہے جو موازنہ کرتا ہے، یعنی موازنہ کرتا ہے۔ اشیاء کے رشتہ دار ترتیب کی نشاندہی کرنے کے لیے، ہم ایک واپس کرتے ہیں int۔ یہ بنیادی طور پر ہے. اچھا اور آسان۔ جیسا کہ آپ مثال سے دیکھ سکتے ہیں، Comparator کے علاوہ، ایک اور انٹرفیس ہے — java.lang.Comparableجو کہ ہم سے compareToطریقہ کو نافذ کرنے کی ضرورت ہے۔ یہ انٹرفیس کہتا ہے، "ایک کلاس جو مجھے لاگو کرتی ہے کلاس کی مثالوں کا موازنہ کرنا ممکن بناتی ہے۔" مثال کے طور پر، To Integerکا نفاذ compareمندرجہ ذیل ہے:
(x < y) ? -1 : ((x == y) ? 0 : 1)
جاوا 8 نے کچھ اچھی تبدیلیاں متعارف کرائی ہیں۔ اگر آپ انٹرفیس کو قریب سے دیکھیں تو Comparatorآپ کو @FunctionalInterfaceاس کے اوپر تشریح نظر آئے گی۔ یہ تشریح معلومات کے مقاصد کے لیے ہے اور ہمیں بتاتی ہے کہ یہ انٹرفیس فعال ہے۔ اس کا مطلب یہ ہے کہ اس انٹرفیس میں صرف 1 تجریدی طریقہ ہے، جو بغیر کسی عمل کے ایک طریقہ ہے۔ یہ ہمیں کیا دیتا ہے؟ اب ہم کمپیریٹر کا کوڈ اس طرح لکھ سکتے ہیں:
Comparator<Message> comparator = (o1, o2) -> o1.getId().compareTo(o2.getId());
ہم متغیرات کو قوسین میں نام دیتے ہیں۔ جاوا دیکھے گا کہ چونکہ صرف ایک طریقہ ہے، اس لیے مطلوبہ تعداد اور ان پٹ پیرامیٹرز کی اقسام واضح ہیں۔ پھر ہم تیر آپریٹر کو کوڈ کے اس حصے میں منتقل کرنے کے لیے استعمال کرتے ہیں۔ مزید کیا ہے، جاوا 8 کی بدولت، اب ہمارے پاس انٹرفیس میں پہلے سے طے شدہ طریقے ہیں۔ یہ طریقے ڈیفالٹ کے طور پر ظاہر ہوتے ہیں جب ہم ایک انٹرفیس کو نافذ کرتے ہیں۔ انٹرفیس Comparatorمیں کئی ہیں۔ مثال کے طور پر:
Comparator moreImportant = Comparator.reverseOrder();
Comparator lessImportant = Comparator.naturalOrder();
ایک اور طریقہ ہے جو آپ کے کوڈ کو صاف ستھرا بنا دے گا۔ اوپر کی مثال پر ایک نظر ڈالیں، جہاں ہم نے اپنے موازنہ کی تعریف کی ہے۔ یہ کیا کرتا ہے؟ یہ کافی قدیم ہے۔ یہ صرف ایک چیز لیتا ہے اور کچھ قدر نکالتا ہے جو "موازنہ" ہے۔ مثال کے طور پر، Integerimpuls comparable، لہذا ہم میسج آئی ڈی فیلڈز کی قدروں پر compareTo آپریشن کرنے کے قابل ہیں۔ اس سادہ کمپیریٹر فنکشن کو اس طرح لکھا جا سکتا ہے:
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
دوسرے لفظوں میں، ہمارے پاس ایک ہے Comparatorجو اس طرح موازنہ کرتا ہے: یہ اشیاء لیتا ہے، ان سے getId()حاصل کرنے کے لیے طریقہ استعمال کرتا ہے Comparable، اور پھر compareToموازنہ کرنے کے لیے استعمال کرتا ہے۔ اور اس سے زیادہ خوفناک تعمیرات نہیں ہیں۔ اور آخر میں، میں ایک اور خصوصیت نوٹ کرنا چاہتا ہوں۔ موازنہ کرنے والوں کو جکڑا جا سکتا ہے۔ مثال کے طور پر:
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
comparator = comparator.thenComparing(obj -> obj.getMessage().length());

درخواست

موازنہ کرنے والے کا اعلان کرنا کافی منطقی نکلا، کیا آپ نہیں سوچتے؟ اب دیکھنا یہ ہے کہ اسے کیسے اور کہاں استعمال کیا جائے۔ → Collections.sort(java.util.Collections) ہم، یقینا، اس طرح مجموعوں کو ترتیب دے سکتے ہیں۔ لیکن ہر مجموعہ نہیں، صرف فہرستیں۔ یہاں کوئی غیر معمولی بات نہیں ہے، کیونکہ فہرستیں اس قسم کے مجموعے ہیں جہاں آپ عناصر کو ان کے انڈیکس کے ذریعے رسائی حاصل کرتے ہیں۔ یہ دوسرے عنصر کو تیسرے عنصر کے ساتھ تبدیل کرنے کی اجازت دیتا ہے۔ اس لیے ترتیب دینے کا درج ذیل طریقہ صرف فہرستوں کے لیے ہے۔
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
Collections.sort(messages, comparator);
Arrays.sort(java.util.Arrays) صفوں کو ترتیب دینا بھی آسان ہے۔ ایک بار پھر، اسی وجہ سے - ان کے عناصر کو انڈیکس کے ذریعے حاصل کیا جاتا ہے۔ → Descendants of java.util.SortedSet and java.util.SortedMap آپ اسے یاد کریں گے Setاور Mapاس ترتیب کی ضمانت نہیں دیں گے جس میں عناصر کو ذخیرہ کیا گیا ہے۔ لیکن، ہمارے پاس خصوصی نفاذ ہیں جو آرڈر کی ضمانت دیتے ہیں۔ اور اگر کسی مجموعہ کے عناصر نافذ نہیں کرتے ہیں ، تو ہم اس کے کنسٹرکٹر کو java.util.Comparableبھیج سکتے ہیں :Comparator
Set<Message> msgSet = new TreeSet(comparator);
Stream API اسٹریم API میں، جو جاوا 8 میں ظاہر ہوا، موازنہ کرنے والے آپ کو اسٹریم عناصر کے ساتھ کام کو آسان بنانے دیتے ہیں۔ مثال کے طور پر، فرض کریں کہ ہمیں 0 سے 999 تک بے ترتیب نمبروں کی ایک ترتیب درکار ہے، بشمول:
Supplier<Integer> randomizer = () -> new Random().nextInt(1000);
Stream.generate(randomizer)
    .limit(10)
    .sorted(Comparator.naturalOrder())
    .forEach(e -> System.out.println(e));
ہم یہاں رک سکتے ہیں، لیکن اس سے بھی زیادہ دلچسپ مسائل ہیں۔ مثال کے طور پر، فرض کریں کہ آپ کو ایک تیار کرنے کی ضرورت ہے Map، جہاں کلید ایک پیغام کی شناخت ہے۔ مزید برآں، ہم ان کلیدوں کو ترتیب دینا چاہتے ہیں، لہذا ہم درج ذیل کوڈ سے شروع کریں گے:
Map<Integer, Message> collected = Arrays.stream(messages)
                .sorted(Comparator.comparing(msg -> msg.getId()))
                .collect(Collectors.toMap(msg -> msg.getId(), msg -> msg));
ہم اصل میں HashMapیہاں ایک حاصل کرتے ہیں. اور جیسا کہ ہم جانتے ہیں، یہ کسی بھی حکم کی ضمانت نہیں دیتا۔ نتیجے کے طور پر، ہمارے عناصر، جو id کے لحاظ سے ترتیب دیئے گئے تھے، اپنی ترتیب سے محروم ہو جاتے ہیں۔ اچھا نہیں. ہمیں اپنے کلکٹر کو تھوڑا سا تبدیل کرنا پڑے گا:
Map<Integer, Message> collected = Arrays.stream(messages)
                .sorted(Comparator.comparing(msg -> msg.getId()))
                .collect(Collectors.toMap(msg -> msg.getId(), msg -> msg, (oldValue, newValue) -> oldValue, TreeMap::new));
کوڈ تھوڑا خوفناک نظر آنے لگا ہے، لیکن اب مسئلہ صحیح طریقے سے حل ہو گیا ہے۔ یہاں مختلف گروہوں کے بارے میں مزید پڑھیں: آپ اپنا کلیکٹر بنا سکتے ہیں۔ یہاں مزید پڑھیں: "جاوا 8 میں ایک کسٹم کلیکٹر بنانا" ۔ اور آپ یہاں بحث کو پڑھنے سے فائدہ اٹھائیں گے: "جاوا 8 لسٹ ٹو میپ ٹو اسٹریم کے ساتھ" ۔

گرنے کا جال

Comparatorاور Comparableاچھے ہیں. لیکن ایک باریکی ہے جو آپ کو یاد رکھنی چاہیے۔ جب کوئی کلاس چھانٹتی ہے تو یہ توقع کرتی ہے کہ آپ کی کلاس کو ایک میں تبدیل کیا جا سکتا ہے Comparable۔ اگر یہ معاملہ نہیں ہے، تو آپ کو رن ٹائم پر ایک خرابی موصول ہوگی۔ آئیے ایک مثال دیکھتے ہیں:
SortedSet<Message> msg = new TreeSet<>();
msg.add(new Message(2, "Developer".getBytes()));
ایسا لگتا ہے کہ یہاں کچھ بھی غلط نہیں ہے۔ لیکن درحقیقت، ہماری مثال میں، یہ ایک غلطی کے ساتھ ناکام ہو جائے گا: java.lang.ClassCastException: Message cannot be cast to java.lang.Comparable اور سب اس لیے کہ اس نے عناصر کو ترتیب دینے کی کوشش کی (یہ ایک ہے SortedSet، آخر کار)...لیکن ایسا نہیں ہو سکا۔ SortedMapاور کے ساتھ کام کرتے وقت اسے مت بھولنا SortedSet۔
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION