برای اعلان کلاسی که Interface پیادهسازی میکند، عبارت implements را در اعلان کلاس قرار میدهید. کلاس شما میتواند بیش از یک Interface پیادهسازی کند، بنابراین کلمهکلیدی implements بعد از لیستی جداشده با کاما از Interfaceهایی که کلاس پیادهسازی میکند میآید. عبارت implements باید بعد از عبارت extends بیاید، اگر وجود داشته باشد.
Interfaceای را در نظر بگیرید که نحوهی مقایسهی اندازهی اشیا را تعریف میکند:
public interface Relatable {
// this (object calling isLargerThan())
// and other must be instances of
// the same class returns 1, 0, -1
// if this is greater than,
// equal to, or less than other
public int isLargerThan(Relatable other);
}
اگر بخواهید بتوانید اندازهی اشیای مشابه را مقایسه کنید، صرفنظر از اینکه چه چیزی هستند، کلاسی که از آنها نمونه میسازد باید Relatable را پیادهسازی کند.
هر کلاسی میتواند Relatable را پیادهسازی کند اگر راهی برای مقایسهی «اندازه» نسبی اشیای نمونهسازیشده از آن کلاس وجود داشته باشد. برای رشتهها میتواند تعداد کاراکترها باشد؛ برای کتابها تعداد صفحات؛ برای دانشجویان وزن؛ و غیره. برای اشیای هندسی مسطح، مساحت انتخاب خوبی است (کلاس RectanglePlus زیر را ببینید)، در حالی که حجم برای اشیای هندسی سهبعدی مناسب است. تمام این کلاسها میتوانند متد isLargerThan() را پیادهسازی کنند.
اگر بدانید کلاسی Relatable را پیادهسازی کرده، میدانید که میتوانید اندازهی اشیای نمونهسازیشده از آن کلاس را مقایسه کنید.
کلاس Rectangle که در بخش ایجاد اشیا ارائه شده بود، اینجا با بازنویسی برای پیادهسازی Relatable آمده است:
public class RectanglePlus
implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
public RectanglePlus() {
origin = new Point(0, 0);
}
public RectanglePlus(Point p) {
origin = p;
}
public RectanglePlus(int w, int h) {
origin = new Point(0, 0);
width = w;
height = h;
}
public RectanglePlus(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
// a method for moving the rectangle
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
// a method for computing
// the area of the rectangle
public int getArea() {
return width * height;
}
// a method required to implement
// the Relatable interface
public int isLargerThan(Relatable other) {
RectanglePlus otherRect
= (RectanglePlus)other;
if (this.getArea() < otherRect.getArea())
return -1;
else if (this.getArea() > otherRect.getArea())
return 1;
else
return 0;
}
}
چون RectanglePlus رابط Relatable را پیادهسازی میکند، میتوان اندازهی هر دو شی RectanglePlus را مقایسه کرد.
---نکته: متد
isLargerThan()همانطور که در InterfaceRelatableتعریف شده، شیای از نوعRelatableمیگیرد. خط کد، other را به یک نمونهRectanglePlusCasting میکند. Type Casting به کامپایلر میگوید شی واقعاً چیست. فراخوانیgetArea()مستقیماً روی نمونهی دیگر (other.getArea()) در کامپایل خطا ایجاد میکند چون کامپایلر نمیداند other واقعاً نمونهای ازRectanglePlusاست.
Interfaceای که توسعه دادهاید به نام DoIt را در نظر بگیرید:
public interface DoIt {
void doSomething(int i, double x);
int doSomethingElse(String s);
}
فرض کنید در زمان بعدی میخواهید متد سومی به DoIt اضافه کنید تا Interface به این صورت درآید. این یک تغییر رایج است اما در عین حال پیامدهای مهمی برای کدهای موجود دارد:
public interface DoIt {
void doSomething(int i, double x);
int doSomethingElse(String s);
boolean didItWork(int i, double x, String s);
}
اگر این تغییر را اعمال کنید، تمام کلاسهایی که Interface قدیمی DoIt را پیادهسازی کردهاند خراب میشوند چون دیگر Interface قدیمی را پیادهسازی نمیکنند. برنامهنویسانی که به این Interface وابسته هستند اعتراض شدیدی خواهند کرد.
سعی کنید تمام کاربردهای Interface خود را پیشبینی و از همان ابتدا آن را کامل مشخص کنید. اگر میخواهید متدهای اضافی به Interface اضافه کنید، چندین گزینه دارید. میتوانید Interface DoItPlus بسازید که از DoIt ارث ببرد:
public interface DoItPlus extends DoIt {
boolean didItWork(int i, double x, String s);
}
حالا کاربران کد شما میتوانند انتخاب کنند که همچنان از Interface قدیمی استفاده کنند یا به Interface جدید ارتقا دهند.
جایگزین این است که متدهای جدید را به صورت Default Method تعریف کنید. مثال زیر یک Default Method به نام didItWork() تعریف میکند:
public interface DoIt {
void doSomething(int i, double x);
int doSomethingElse(String s);
default boolean didItWork(int i, double x, String s) {
// Method body
}
}
توجه کنید که باید پیادهسازی Default Methodها را فراهم کنید. همچنین میتوانید متدهای static جدید به Interfaceهای موجود تعریف کنید.
کاربرانی که کلاسهایی دارند که Interfaceهای غنیشده با Default Method یا Static Methodهای جدید را پیادهسازی میکنند، مجبور نیستند برای سازگاری با متدهای اضافی، کلاسهایشان را تغییر یا دوباره کامپایل کنند، به شرطی که این Default Methodهای جدید با هیچ متد موجود از Interfaceهای دیگری که توسط آن کلاسها پیادهسازی شده تداخل نداشته باشند.
---بخش Interfaceها مثالی را توصیف میکند که شامل تولیدکنندگان ماشینهای کنترلشده با کامپیوتر است که Interfaceهای استاندارد صنعتی منتشر میکنند و مشخص میکنند چه متدهایی میتوانند برای عملیات ماشینهایشان فراخوانی شوند. اگر آن تولیدکنندگان ماشین، قابلیتهای جدیدی مثل پرواز به ماشینهایشان اضافه کنند چه؟ این تولیدکنندگان باید متدهای جدیدی مشخص کنند تا شرکتهای دیگر (مثل تولیدکنندگان ابزارهای راهنمای الکترونیکی) بتوانند نرمافزارشان را با ماشینهای پرنده سازگار کنند. این تولیدکنندگان متدهای مرتبط با پرواز را کجا اعلان میکنند؟ اگر آنها را به Interfaceهای اصلی اضافه کنند، برنامهنویسانی که آن Interfaceها را پیادهسازی کردهاند مجبور میشوند پیادهسازیشان را بازنویسی کنند. اگر آنها را به صورت Static Method اضافه کنند، برنامهنویسان آنها را متدهای کمکی تلقی میکنند، نه متدهای اصلی و حیاتی.
Default Methodها به شما اجازه میدهند قابلیت جدید به Interfaceهای کتابخانههایتان اضافه کنید و سازگاری باینری (Binary Compatibility) با کد نوشتهشده برای نسخههای قدیمیتر آن Interfaceها را تضمین کنید. مطمئن شوید Default Methodهایی که اضافه میکنید با هیچ متد موجود از Interfaceهای دیگری که توسط آن کلاسها پیادهسازی شده تداخل نداشته باشند.
Interface TimeClient زیر را در نظر بگیرید:
import java.time.*;
public interface TimeClient {
void setTime(int hour, int minute, int second);
void setDate(int day, int month, int year);
void setDateAndTime(int day, int month, int year,
int hour, int minute, int second);
LocalDateTime getLocalDateTime();
}
کلاس SimpleTimeClient زیر Interface TimeClient را پیادهسازی میکند:
public class SimpleTimeClient implements TimeClient {
private LocalDateTime dateAndTime;
public SimpleTimeClient() {
dateAndTime = LocalDateTime.now();
}
public void setTime(int hour, int minute, int second) {
LocalDate currentDate = LocalDate.from(dateAndTime);
LocalTime timeToSet = LocalTime.of(hour, minute, second);
dateAndTime = LocalDateTime.of(currentDate, timeToSet);
}
public void setDate(int day, int month, int year) {
LocalDate dateToSet = LocalDate.of(day, month, year);
LocalTime currentTime = LocalTime.from(dateAndTime);
dateAndTime = LocalDateTime.of(dateToSet, currentTime);
}
public void setDateAndTime(int day, int month, int year,
int hour, int minute, int second) {
LocalDate dateToSet = LocalDate.of(day, month, year);
LocalTime timeToSet = LocalTime.of(hour, minute, second);
dateAndTime = LocalDateTime.of(dateToSet, timeToSet);
}
public LocalDateTime getLocalDateTime() {
return dateAndTime;
}
public String toString() {
return dateAndTime.toString();
}
public static void main(String... args) {
TimeClient myTimeClient = new SimpleTimeClient();
IO.println(myTimeClient.toString());
}
}
فرض کنید میخواهید قابلیت جدیدی به Interface TimeClient اضافه کنید، مثلاً توانایی مشخص کردن منطقهی زمانی از طریق شی ZonedDateTime (که شبیه LocalDateTime است اما اطلاعات منطقهی زمانی را هم ذخیره میکند):
public interface TimeClient {
void setTime(int hour, int minute, int second);
void setDate(int day, int month, int year);
void setDateAndTime(int day, int month, int year,
int hour, int minute, int second);
LocalDateTime getLocalDateTime();
ZonedDateTime getZonedDateTime(String zoneString);
}
بعد از این تغییر در Interface TimeClient، باید کلاس SimpleTimeClient را هم تغییر دهید و متد getZonedDateTime() را پیادهسازی کنید. اما به جای اینکه getZonedDateTime() را Abstract نگه دارید (مثل مثال قبل)، میتوانید به جای آن یک پیادهسازی پیشفرض تعریف کنید. (به یاد داشته باشید که Abstract Method متدی است که بدون پیادهسازی اعلان شده.)
public interface TimeClient {
void setTime(int hour, int minute, int second);
void setDate(int day, int month, int year);
void setDateAndTime(int day, int month, int year,
int hour, int minute, int second);
LocalDateTime getLocalDateTime();
static ZoneId getZoneId (String zoneString) {
try {
return ZoneId.of(zoneString);
} catch (DateTimeException e) {
System.err.println("Invalid time zone: " + zoneString +
"; using default time zone instead.");
return ZoneId.systemDefault();
}
}
default ZonedDateTime getZonedDateTime(String zoneString) {
return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
}
}
شما با کلمهکلیدی default در ابتدای Signature متد مشخص میکنید که تعریف متد در Interface یک Default Method است. تمام اعلانهای متد در Interface، شامل Default Methodها، بهصورت ضمنی public هستند، بنابراین میتوانید ویرایشگر public را حذف کنید.
با این Interface، مجبور نیستید کلاس SimpleTimeClient را تغییر دهید و این کلاس (و هر کلاسی که Interface TimeClient را پیادهسازی کند) متد getZonedDateTime() را از قبل تعریفشده خواهد داشت. مثال TestSimpleTimeClient زیر متد getZonedDateTime() را از یک نمونهی SimpleTimeClient فراخوانی میکند:
public class TestSimpleTimeClient {
public static void main(String... args) {
TimeClient myTimeClient = new SimpleTimeClient();
IO.println("Current time: " + myTimeClient.toString());
IO.println("Time in California: " +
myTimeClient.getZonedDateTime("Blah blah").toString());
}
}
---
وقتی Interfaceای که Default Method دارد را گسترش میدهید، میتوانید کارهای زیر را انجام دهید:
TimeClient را به این صورت گسترش میدهید:public interface AnotherTimeClient extends TimeClient { }
هر کلاسی که Interface AnotherTimeClient را پیادهسازی کند، پیادهسازی مشخصشده توسط Default Method TimeClient.getZonedDateTime() را خواهد داشت.
فرض کنید Interface TimeClient را به این صورت گسترش میدهید:
public interface AbstractZoneTimeClient extends TimeClient {
public ZonedDateTime getZonedDateTime(String zoneString);
}
هر کلاسی که Interface AbstractZoneTimeClient را پیادهسازی کند، باید متد getZonedDateTime() را پیادهسازی کند؛ این متد یک Abstract Method است مثل تمام متدهای غیرپیشفرض (و غیراستاتیک) دیگر در Interface.
فرض کنید Interface TimeClient را به این صورت گسترش میدهید:
public interface HandleInvalidTimeZoneClient extends TimeClient {
default public ZonedDateTime getZonedDateTime(String zoneString) {
try {
return ZonedDateTime.of(getLocalDateTime(),ZoneId.of(zoneString));
} catch (DateTimeException e) {
System.err.println("Invalid zone ID: " + zoneString +
"; using the default time zone instead.");
return ZonedDateTime.of(getLocalDateTime(),ZoneId.systemDefault());
}
}
}
هر کلاسی که Interface HandleInvalidTimeZoneClient را پیادهسازی کند، از پیادهسازی getZonedDateTime() مشخصشده توسط این Interface به جای آنچه Interface TimeClient مشخص کرده استفاده خواهد کرد.
علاوه بر Default Methodها، میتوانید Static Methodها را در Interfaceها تعریف کنید. (متد Static متدی است که با کلاسی که در آن تعریف شده مرتبط است نه با هیچ شیای. هر نمونه از کلاس، Static Methodهایش را به اشتراک میگذارد.) این کار سازماندهی متدهای کمکی در کتابخانههایتان را آسانتر میکند؛ میتوانید Static Methodهای مخصوص یک Interface را در همان Interface نگه دارید نه در کلاسی جداگانه. مثال زیر یک Static Method تعریف میکند که شی ZoneId متناظر با یک شناسهی منطقهی زمانی را بازیابی میکند؛ اگر ZoneId متناظری برای شناسهی دادهشده وجود نداشته باشد، از منطقهی زمانی پیشفرض سیستم استفاده میکند. (در نتیجه میتوانید متد getZonedDateTime() را سادهتر کنید):
public interface TimeClient {
// ...
static public ZoneId getZoneId (String zoneString) {
try {
return ZoneId.of(zoneString);
} catch (DateTimeException e) {
System.err.println("Invalid time zone: " + zoneString +
"; using default time zone instead.");
return ZoneId.systemDefault();
}
}
default public ZonedDateTime getZonedDateTime(String zoneString) {
return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
}
}
مثل متدهای Static در کلاسها، شما با کلمهکلیدی static در ابتدای Signature متد مشخص میکنید که تعریف متد در Interface یک Static Method است. تمام اعلانهای متد در Interface، شامل Static Methodها، بهصورت ضمنی public هستند، بنابراین میتوانید ویرایشگر public را حذف کنید.
از جاوا SE 9 به بعد، میتوانید متدهای private در Interface تعریف کنید تا بخش مشترکی از کد را از Default Methodهای Interface استخراج کنید در حالی که پیادهسازی آن را تعریف میکنید. این متدها به پیادهسازی تعلق دارند و نمیتوانند default یا abstract باشند. مثلاً میتوانید متد getZoneId را private کنید چون بخشی از کد است که درون پیادهسازی Interface داخلی است.
Default Methodها به شما اجازه میدهند قابلیت جدید به Interfaceهای موجود اضافه کنید و سازگاری باینری با کد نوشتهشده برای نسخههای قدیمیتر آن Interfaceها را تضمین کنید. بهطور خاص، Default Methodها به شما اجازه میدهند متدهایی که Lambda Expressionها را به عنوان پارامتر میپذیرند به Interfaceهای موجود اضافه کنید. این بخش نشان میدهد چگونه Interface Comparator با Default Method و Static Method غنی شده است.
کلاسهای Card و Deck را در نظر بگیرید. Interface Card شامل دو نوع enum (Suit و Rank) و دو Abstract Method (getSuit() و getRank()) است:
public interface Card extends Comparable<Card> {
public enum Suit {
DIAMONDS (1, "Diamonds"),
CLUBS (2, "Clubs" ),
HEARTS (3, "Hearts" ),
SPADES (4, "Spades" );
private final int value;
private final String text;
Suit(int value, String text) {
this.value = value;
this.text = text;
}
public int value() {return value;}
public String text() {return text;}
}
public enum Rank {
DEUCE (2 , "Two" ),
THREE (3 , "Three"),
FOUR (4 , "Four" ),
FIVE (5 , "Five" ),
SIX (6 , "Six" ),
SEVEN (7 , "Seven"),
EIGHT (8 , "Eight"),
NINE (9 , "Nine" ),
TEN (10, "Ten" ),
JACK (11, "Jack" ),
QUEEN (12, "Queen"),
KING (13, "King" ),
ACE (14, "Ace" );
private final int value;
private final String text;
Rank(int value, String text) {
this.value = value;
this.text = text;
}
public int value() {return value;}
public String text() {return text;}
}
public Card.Suit getSuit();
public Card.Rank getRank();
}
Interface Deck شامل متدهای مختلفی برای دستکاری کارتها در یک دسته است:
public interface Deck {
List<Card> getCards();
Deck deckFactory();
int size();
void addCard(Card card);
void addCards(List<Card> cards);
void addDeck(Deck deck);
void shuffle();
void sort();
void sort(Comparator<Card> c);
String deckToString();
Map<Integer, Deck> deal(int players, int numberOfCards)
throws IllegalArgumentException;
}
کلاس PlayingCard Interface Card و کلاس StandardDeck Interface Deck را پیادهسازی میکند.
public class PlayingCard implements Card {
private Rank rank;
private Suit suit;
// constructor
// implementations of Card abstract methods
public Suit getSuit() {
return this.suit;
}
public Rank getRank() {
return this.rank;
}
// implementation of Comparable<Card> method
public int compareTo(Card o) {
return this.hashCode() - o.hashCode();
}
// toString, equals, hashCode
}
کلاس StandardDeck Abstract Method Deck.sort() را به این صورت پیادهسازی میکند:
public class StandardDeck implements Deck {
private List<Card> entireDeck;
// constructor, accessors
// you need to add all the methods from Deck
public void sort() {
Collections.sort(entireDeck);
}
// toString, equals, hashCode
}
متد Collections.sort() نمونهای از List را مرتب میکند که نوع عناصرش Interface Comparable را پیادهسازی کرده باشد. عضو entireDeck نمونهای از List است که عناصرش از نوع Card هستند که از Comparable ارث میبرد. کلاس PlayingCard متد Comparable.compareTo() را به این صورت پیادهسازی میکند:
public int hashCode() {
return ((suit.value()-1)*13)+rank.value();
}
public int compareTo(Card o) {
return this.hashCode() - o.hashCode();
}
متد compareTo() باعث میشود متد StandardDeck.sort() دسته کارتها را ابتدا بر اساس نوع خال (Suit) و سپس بر اساس رتبه (Rank) مرتب کند.
اگر بخواهید ابتدا بر اساس رتبه و سپس بر اساس خال مرتب کنید چه؟ باید Interface Comparator را پیادهسازی کنید تا معیارهای مرتبسازی جدید مشخص شوند و از متد sort(List<T> list, Comparator<? super T> c) (نسخهای از متد sort که پارامتر Comparator دارد) استفاده کنید. متد زیر را میتوانید در کلاس StandardDeck تعریف کنید:
public void sort(Comparator<Card> c) {
Collections.sort(entireDeck, c);
}
با این متد، میتوانید مشخص کنید متد Collections.sort() نمونههای کلاس Card را چگونه مرتب کند. یک راه این است که Interface Comparator را پیادهسازی کنید تا نحوهی مرتبسازی کارتها مشخص شود. مثال SortByRankThenSuit این کار را انجام میدهد:
public class SortByRankThenSuit implements Comparator<Card> {
public int compare(Card firstCard, Card secondCard) {
int compVal =
firstCard.getRank().value() - secondCard.getRank().value();
if (compVal != 0)
return compVal;
else
return firstCard.getSuit().value() - secondCard.getSuit().value();
}
}
فراخوانی زیر دسته کارتها را ابتدا بر اساس رتبه و سپس بر اساس خال مرتب میکند:
StandardDeck myDeck = new StandardDeck();
myDeck.shuffle();
myDeck.sort(new SortByRankThenSuit());
اما این رویکرد بیش از حد طولانی است؛ بهتر بود فقط معیارهای مرتبسازی را مشخص کنید و از ایجاد پیادهسازیهای مرتبسازی متعدد اجتناب کنید. فرض کنید توسعهدهندهای هستید که Interface Comparator را نوشتهاید. چه Default Method یا Static Methodهایی میتوانید به Interface Comparator اضافه کنید تا توسعهدهندگان دیگر راحتتر بتوانند معیارهای مرتبسازی را مشخص کنند؟
برای شروع، فرض کنید میخواهید دسته کارتها را بر اساس رتبه مرتب کنید، صرفنظر از خال. میتوانید متد StandardDeck.sort() را به این صورت فراخوانی کنید:
StandardDeck myDeck = new StandardDeck();
myDeck.shuffle();
myDeck.sort(
(firstCard, secondCard) ->
firstCard.getRank().value() - secondCard.getRank().value()
);
چون Interface Comparator یک Functional Interface است، میتوانید از Lambda Expression به عنوان آرگومان متد sort() استفاده کنید. در این مثال، Lambda Expression دو مقدار عددی را مقایسه میکند.
برای توسعهدهندگان شما سادهتر خواهد بود اگر بتوانند نمونهی Comparator را فقط با فراخوانی متد Card.getRank() بسازند. بهویژه مفید خواهد بود اگر توسعهدهندگان شما بتوانند نمونهی Comparator بسازند که هر شیای را مقایسه کند که مقدار عددی از متدی مثل getValue() یا hashCode() برمیگرداند. Interface Comparator با Static Method comparing با این قابلیت غنی شده است:
myDeck.sort(Comparator.comparing((card) -> card.getRank()));
در این مثال، میتوانید به جای آن از Method Reference استفاده کنید:
myDeck.sort(Comparator.comparing(Card::getRank));
این فراخوانی بهتر نشان میدهد چگونه معیارهای مرتبسازی متفاوت مشخص کنید و از ایجاد پیادهسازیهای مرتبسازی متعدد اجتناب کنید.
Interface Comparator با نسخههای دیگری از Static Method comparing مثل comparingDouble() و comparingLong() غنی شده که به شما اجازه میدهند نمونههای Comparator بسازید که انواع دادهای دیگر را مقایسه کنند.
فرض کنید توسعهدهندگان شما میخواهند نمونهی Comparator بسازند که بتواند اشیا را با بیش از یک معیار مقایسه کند. مثلاً چگونه دسته کارتها را ابتدا بر اساس رتبه و سپس بر اساس خال مرتب میکنید؟ مثل قبل، میتوانید از Lambda Expression استفاده کنید:
StandardDeck myDeck = new StandardDeck();
myDeck.shuffle();
myDeck.sort(
(firstCard, secondCard) -> {
int compare =
firstCard.getRank().value() - secondCard.getRank().value();
if (compare != 0)
return compare;
else
return firstCard.getSuit().value() - secondCard.getSuit().value();
}
);
برای توسعهدهندگان شما سادهتر خواهد بود اگر بتوانند نمونهی Comparator را از سری نمونههای Comparator بسازند. Interface Comparator با Default Method thenComparing() با این قابلیت غنی شده است:
myDeck.sort(
Comparator
.comparing(Card::getRank)
.thenComparing(Comparator.comparing(Card::getSuit)));
Interface Comparator با نسخههای دیگری از Default Method thenComparing() غنی شده:
thenComparing(Function): تابعی میگیرد که کلیدی برای مقایسهی عناصر استخراج میکند. توجه کنید این کلید باید نمونهای از Comparable باشد.thenComparingInt()، thenComparingLong() و thenComparingDouble() که همان کار Overload قبلی را انجام میدهند اما بدون هزینهی Boxing و Unboxing کلید.میتوانید از Overload اول برای بازنویسی مثال قبلی به شکل سادهتر استفاده کنید:
myDeck.sort(
Comparator
.comparing(Card::getRank)
.thenComparing(Card::getSuit));
فرض کنید توسعهدهندگان شما میخواهند نمونهی Comparator بسازند که بتوانند مجموعهای از اشیا را به ترتیب معکوس مرتب کنند. مثلاً چگونه دسته کارتها را به ترتیب نزولی رتبه مرتب میکنید، از Ace تا Two (به جای Two تا Ace)؟ مثل قبل، میتوانید Lambda Expression دیگری مشخص کنید. اما برای توسعهدهندگان شما سادهتر خواهد بود اگر بتوانند Comparator موجود را با فراخوانی یک متد معکوس کنند. Interface Comparator با Default Method reversed() با این قابلیت غنی شده است:
myDeck.sort(
Comparator.comparing(Card::getRank)
.reversed()
.thenComparing(Comparator.comparing(Card::getSuit)));
این مثال نشان میدهد Interface Comparator چگونه با Default Methodها، Static Methodها، Lambda Expressionها و Method Referenceها غنی شده تا متدهای کتابخانهای بیانگرتری ایجاد شود که برنامهنویسان بتوانند عملکردشان را با نگاه کردن به نحوهی فراخوانیشان به سرعت دریابند. از این سازهها برای غنیسازی Interfaceهای کتابخانههایتان استفاده کنید.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/