CodeGym/Java Blogu/Rastgele/Java'nın Karşılaştırıcı arabirimi
John Squirrels
Seviye
San Francisco

Java'nın Karşılaştırıcı arabirimi

grupta yayınlandı
Java'da Karşılaştırıcılar ve karşılaştırmalar hakkında yazanlar yalnızca tembeller değildir. Tembel değilim, bu yüzden lütfen başka bir açıklama için sevin ve yakının. Umarım gereksiz olmaz. Ve evet, bu makale şu sorunun cevabıdır: " Hafızadan bir karşılaştırıcı yazabilir misiniz? " Umarım herkes bu makaleyi okuduktan sonra bellekten bir karşılaştırıcı yazabilir. Java Karşılaştırıcı arabirimi - 1

giriiş

Bildiğiniz gibi Java nesne yönelimli bir dildir. Sonuç olarak, Java'da nesneleri işlemek alışılmış bir durumdur. Ancak er ya da geç, bazı özelliklere göre nesneleri karşılaştırma göreviyle karşı karşıya kalırsınız. Örneğin : Diyelim ki sınıf tarafından tanımlanan bir mesajımız var 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;
    }
}
Bu sınıfı Tutorialspoint Java derleyicisine koyun . import ifadelerini de eklemeyi unutmayın:
import java.util.Random;
import java.util.ArrayList;
import java.util.List;
Yöntemde mainbirkaç mesaj oluşturun:
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);
}
Bunları karşılaştırmak isteseydik ne yapardık bir düşünelim. Örneğin, id'ye göre sıralamak istiyoruz. Ve bir düzen oluşturmak için, hangi nesnenin önce gelmesi gerektiğini (yani daha küçük olan) ve hangisinin onu takip etmesi gerektiğini (yani daha büyük olan) anlamak için nesneleri bir şekilde karşılaştırmamız gerekir. Java.lang.Object gibi bir sınıfla başlayalım . Tüm sınıfların dolaylı olarak sınıfı miras aldığını biliyoruz Object. Bu da mantıklı çünkü "her şey bir nesnedir" kavramını yansıtıyor ve tüm sınıflar için ortak davranış sağlıyor. Bu sınıf, her sınıfın iki yöntemi olduğunu belirtir: → hashCode Yöntem hashCode, bazı sayısal (int) nesnenin temsili. Bu ne anlama gelir? Bu, bir sınıfın iki farklı örneğini oluşturursanız, bunların farklı hashCodes'lere sahip olması gerektiği anlamına gelir. Yöntemin açıklaması şu kadarını söylüyor: "Makul ölçüde pratik olduğu kadar, Object sınıfı tarafından tanımlanan hashCode yöntemi, farklı nesneler için farklı tamsayılar döndürür". Diğer bir deyişle, iki farklı instances için farklı s olmalıdır hashCode. Yani bu yöntem bizim karşılaştırmamız için uygun değil. → equals. Yöntem equals, "bu nesneler eşit mi?" Sorusunu yanıtlar. ve bir " döndürür boolean." Varsayılan olarak, bu yöntem aşağıdaki koda sahiptir:
public boolean equals(Object obj) {
    return (this == obj);
}
Yani, eğer bu metot geçersiz kılınmazsa, temelde nesne referanslarının eşleşip eşleşmediğini söyler. Mesajlarımız için istediğimiz bu değil, çünkü biz mesaj kimlikleriyle ilgileniyoruz, nesne referanslarıyla değil. Yöntemi geçersiz kılsak bile equals, en fazla umabileceğimiz şey, eşit olup olmadıklarını öğrenmektir. Ve bu sıralamayı belirlememiz için yeterli değil. Peki o zaman neye ihtiyacımız var? Karşılaştırılan bir şeye ihtiyacımız var. Kıyas yapan kişi bir Comparator. Java API'sini açın ve Comparator öğesini bulun . java.util.ComparatorGerçekten, bir arayüz varjava.util.Comparator and java.util.Comparable Gördüğünüz gibi böyle bir arayüz var. Bunu uygulayan bir sınıf, "Nesneleri karşılaştıran bir yöntem uyguluyorum" der. Gerçekten hatırlamanız gereken tek şey, aşağıdaki gibi ifade edilen karşılaştırmalı sözleşmedir:
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
Şimdi bir karşılaştırıcı yazalım. ithal etmemiz gerekecek java.util.Comparator. import deyiminden sonra metoda şunu ekleyin main: Elbette bu bir arayüz olduğu Comparator<Message> comparator = new Comparator<Message>(); için çalışmaz . Bu yüzden parantezlerden sonra Comparatorkaşlı ayraçlar ekliyoruz . {}Parantezlerin içine aşağıdaki yöntemi yazın:
public int compare(Message o1, Message o2) {
    return o1.getId().compareTo(o2.getId());
}
Yazımı hatırlamanıza bile gerek yok. Karşılaştırıcı, karşılaştırma yapan, yani karşılaştıran kişidir. Nesnelerin göreceli sırasını belirtmek için bir döndürürüz int. Temelde bu. Güzel ve kolay. Örnekten de görebileceğiniz gibi, Comparator'a ek olarak, yöntemi java.lang.Comparableuygulamamızı gerektiren — başka bir arabirim var compareTo. Bu arayüz, "beni uygulayan bir sınıf, sınıfın örneklerini karşılaştırmayı mümkün kılar" diyor. Örneğin, Integeröğesinin compareTo uygulaması aşağıdaki gibidir:
(x < y) ? -1 : ((x == y) ? 0 : 1)
Java 8 bazı güzel değişiklikler getirdi. Arayüze daha yakından bakarsanız , üzerinde ek açıklama Comparatorgöreceksiniz . @FunctionalInterfaceBu ek açıklama bilgi amaçlıdır ve bize bu arayüzün işlevsel olduğunu söyler. Bu, bu arayüzün yalnızca 1 soyut yöntemi olduğu anlamına gelir; bu, uygulaması olmayan bir yöntemdir. Bu bize ne veriyor? Şimdi karşılaştırıcının kodunu şu şekilde yazabiliriz:
Comparator<Message> comparator = (o1, o2) -> o1.getId().compareTo(o2.getId());
Değişkenleri parantez içinde adlandırıyoruz. Java, yalnızca bir yöntem olduğu için, gerekli sayıda ve giriş parametresi türünün net olduğunu görecektir. Sonra onları kodun bu kısmına geçirmek için ok operatörünü kullanırız. Dahası, Java 8 sayesinde artık arayüzlerde varsayılan yöntemlere sahibiz. Bir arabirim uyguladığımızda bu yöntemler varsayılan olarak görünür. Arayüzde Comparatorbirkaç tane var. Örneğin:
Comparator moreImportant = Comparator.reverseOrder();
Comparator lessImportant = Comparator.naturalOrder();
Kodunuzu daha temiz hale getirecek başka bir yöntem var. Karşılaştırıcımızı tanımladığımız yukarıdaki örneğe bir göz atın. Bu ne işe yarıyor? Oldukça ilkel. Basitçe bir nesneyi alır ve "karşılaştırılabilir" bir değer çıkarır. Örneğin, Integerimplements comparable, böylece mesaj kimliği alanlarının değerleri üzerinde bir CompareTo işlemi gerçekleştirebiliriz. Bu basit karşılaştırma işlevi şu şekilde yazılabilir:
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
Başka bir deyişle, şu şekilde karşılaştıran bir a'ya sahibiz Comparator: nesneleri alır, onlardan getId()a almak için yöntemi kullanır ve sonra karşılaştırmak için kullanır. Ve artık korkunç yapılar yok. Ve son olarak, bir özelliği daha not etmek istiyorum. Karşılaştırıcılar zincirlenebilir. Örneğin: ComparablecompareTo
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
comparator = comparator.thenComparing(obj -> obj.getMessage().length());

Başvuru

Bir karşılaştırıcı ilan etmek oldukça mantıklı görünüyor, sence de öyle değil mi? Şimdi onu nasıl ve nerede kullanacağımıza bakmamız gerekiyor. → Collections.sort(java.util.Collections) Elbette koleksiyonları bu şekilde sıralayabiliriz. Ancak her koleksiyon değil, yalnızca listeler. Burada sıra dışı bir şey yok, çünkü listeler, öğelere dizinlerine göre eriştiğiniz türden koleksiyonlardır. Bu, ikinci elemanın üçüncü elemanla değiştirilmesine izin verir. Bu nedenle, aşağıdaki sıralama yöntemi yalnızca listeler içindir:
Comparator<Message> comparator = Comparator.comparing(obj -> obj.getId());
Collections.sort(messages, comparator);
Arrays.sort(java.util.Arrays) Dizileri sıralamak da kolaydır. Yine aynı nedenle — elemanlarına indeks ile erişilir. → Descendants of java.util.SortedSet and java.util.SortedMap Bunu hatırlayacaksınız Setve Mapöğelerin saklanma sırasını garanti etmeyeceksiniz. AMA, düzeni garanti eden özel uygulamalarımız var. Ve bir koleksiyonun öğeleri implement etmezse , o zaman a'yı yapıcısına java.util.Comparableiletebiliriz :Comparator
Set<Message> msgSet = new TreeSet(comparator);
Stream API Java 8'de görünen Akış API'sinde, karşılaştırıcılar, akış öğeleriyle çalışmayı basitleştirmenizi sağlar. Örneğin, 0'dan 999'a kadar bir rasgele sayı dizisine ihtiyacımız olduğunu varsayalım:
Supplier<Integer> randomizer = () -> new Random().nextInt(1000);
Stream.generate(randomizer)
    .limit(10)
    .sorted(Comparator.naturalOrder())
    .forEach(e -> System.out.println(e));
Burada durabiliriz ama daha da ilginç sorunlar var. MapÖrneğin, anahtarın bir mesaj kimliği olduğu bir , hazırlamanız gerektiğini varsayalım . Ek olarak, bu anahtarları sıralamak istiyoruz, bu nedenle aşağıdaki kodla başlayacağız:
Map<Integer, Message> collected = Arrays.stream(messages)
                .sorted(Comparator.comparing(msg -> msg.getId()))
                .collect(Collectors.toMap(msg -> msg.getId(), msg -> msg));
Aslında burada bir tane alıyoruz HashMap. Ve bildiğimiz gibi, herhangi bir düzeni garanti etmez. Sonuç olarak, kimliğe göre sıralanan öğelerimiz sıralarını kaybederler. İyi değil. Koleksiyoncumuzu biraz değiştirmemiz gerekecek:
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));
Kod biraz daha korkutucu görünmeye başladı, ancak şimdi sorun doğru bir şekilde çözüldü. Burada çeşitli gruplamalar hakkında daha fazla bilgi edinin: Kendi toplayıcınızı oluşturabilirsiniz. Burada daha fazlasını okuyun: "Java 8'de özel bir toplayıcı oluşturma" . Ve buradaki tartışmayı okumaktan yararlanacaksınız: "Akışla eşlemek için Java 8 listesi" .

düşme tuzağı

Comparatorve Comparableiyiler Ama hatırlamanız gereken bir nüans var. Bir sınıf sıralama gerçekleştirdiğinde, sınıfınızın bir Comparable. Durum böyle değilse, çalışma zamanında bir hata alırsınız. Bir örneğe bakalım:
SortedSet<Message> msg = new TreeSet<>();
msg.add(new Message(2, "Developer".getBytes()));
Görünüşe göre burada yanlış bir şey yok. Ama aslında, bizim örneğimizde, bir hatayla başarısız olacaktır: java.lang.ClassCastException: Message cannot be cast to java.lang.Comparable Ve bunun nedeni, öğeleri sıralamaya çalışmasıdır (ne de olsa bu bir SortedSet,)... ama başaramadı. SortedMapve ile çalışırken bunu unutmayın SortedSet.
Yorumlar
  • Popüler
  • Yeni
  • Eskimiş
Yorum bırakmak için giriş yapmalısınız
Bu sayfada henüz yorum yok