Java 學習記錄64 — Collections Overview 4/4

張小雄
9 min readMay 26, 2021

--

MainTheatre.java 改

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MainTheatre {
public static void main(String[] args) {
Theatre theatre = new Theatre("Muzha Guangming", 8, 10);
List<Theatre.Seat> seatCopy = new ArrayList<>(theatre.seats);
Collections.shuffle(seatCopy);
sortList(seatCopy);
System.out.println("Printing sorted seat seat copy");
printList(seatCopy);
} public static void printList(List<Theatre.Seat> list) {
for (Theatre.Seat seat : list) {
System.out.print(" " + seat.getSeatNumber());
}
System.out.println();
System.out.println("================================");
}
public static void sortList(List<? extends Theatre.Seat> list) {
for (int i = 0; i < list.size() - 1; i++) {
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).compareTo(list.get(j)) > 0) {
Collections.swap(list, i, j);
}
}
}
}
}

輸出結果:

Printing sorted seat seat copy

A01 A02 A03 A04 A05 A06 A07 A08 A09 A10 B01 B02 B03 B04 B05 B06 B07 B08 B09 B10 C01 C02 C03 C04 C05 C06 C07 C08 C09 C10 D01 D02 D03 D04 D05 D06 D07 D08 D09 D10 E01 E02 E03 E04 E05 E06 E07 E08 E09 E10 F01 F02 F03 F04 F05 F06 F07 F08 F09 F10 G01 G02 G03 G04 G05 G06 G07 G08 G09 G10 H01 H02 H03 H04 H05 H06 H07 H08 H09 H10

================================

用了不同於之前練習的 bubble sort 來排順序

內部 for 是從 外部 for 的後一位開始

所以到後面會越算越少

bubble sort 速度比 merge sort 還慢

而 merge sort 雖然快但資料量大的話,需要的記憶體也跟著多很多

bubble sort 適合用於記憶體為優先考量以及對速度不是那麼在意

另外,使用了 generic,不像 printlist 的參數只能使用 Theatre.seat

在 sortList 的參數則可以使用 Theatre.seat 和繼承於它的子類們

當然前提是它們都有 implement comparable 才能

補充:

Upper Bounded Wildcards

Bubble sort in 2 minutes

Merge Sort vs Quick Sort

MainTheatre.java 改

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MainTheatre {
public static void main(String[] args) {
Theatre theatre = new Theatre("Muzha Guangming", 8, 10);
List<Theatre.Seat> seatCopy = new ArrayList<>(theatre.seats);
// Collections.shuffle(seatCopy);
// sortList(seatCopy);
// System.out.println("Printing sorted seat seat copy");
// printList(seatCopy);
List<Theatre.Seat> newList = new ArrayList<>(theatre.seats.size());
Collections.copy(newList, theatre.seats);
} public static void printList(List<Theatre.Seat> list) {
for (Theatre.Seat seat : list) {
System.out.print(" " + seat.getSeatNumber());
}
System.out.println();
System.out.println("================================");
}
public static void sortList(List<? extends Theatre.Seat> list) {
for (int i = 0; i < list.size() - 1; i++) {
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).compareTo(list.get(j)) > 0) {
Collections.swap(list, i, j);
}
}
}
}
}

輸出結果:

Exception in thread “main” java.lang.IndexOutOfBoundsException: Source does not fit in dest

at java.base/java.util.Collections.copy(Collections.java:561)

at MainTheatre.main(MainTheatre.java:16)

Tim 說一般我們會這樣寫 new ArrayList<>(theatre.seats.size())

但這樣寫雖然沒提示錯誤,但程序試跑不起來的

Tim 說:

Now, the reason that’s fouled is the code on line 37,what that does, it only sets the capacity of the arra

giving it the potential to hold that many elements but initially containing none.

So it still doesn’t actually create a number of elements.

So to get this to work get the copy to work you actually need to have 96 seed objects in that new list in that list that we created on line 37 before we can attempt to copy.

So with that said it’s really hard to think of an actual use for the collections copy method would that would allow all of the elements of a list to be copied into another collections object providing the object had been initialized by enough elements first And I guess that’s probably why it was included.

我看了幾次也還是很迷糊,大意應該是說,如果要用 colletions 的 copy,不能只設一個容量大小

補充:

Salahelden Ibrahim Mohammed 問:

in this code List<Theatre.Seat> seatCopy = new ArrayList<>(theatre.seats);

why we add theatre.seats in the constructor of the ArrayList when i tried to run it without it the program did not print anything

Ulrich

The elements of the arraylist seats (instance variable of object Theatre) are copied to the new Arraylist seatCopy.

Theatre.java 改

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class Theatre {
private final String theatreName;
private List<Seat> seats = new ArrayList<>();
public Theatre(String theatreName, int numRows, int seatsPerRow) {
this.theatreName = theatreName;
int lastRow = 'A' + (numRows - 1);
for (char row = 'A'; row <= lastRow; row++) {
for (int seatNum = 1; seatNum <= seatsPerRow; seatNum++) {
double price = 12.00;
if ((row < 'D') && (seatNum >= 4) && (seatNum <= 9)) {
price = 14.00;
} else if ((row > 'F') || (seatNum < 4) || (seatNum > 9)) {
price = 7.00;
}
Seat seat = new Seat(row + String.format("%02d", seatNum), price);
seats.add(seat);
}
}
}
public String getTheatreName() {
return theatreName;
}
public boolean reserveSeat(String seatNumber) {
Seat requestSeat = new Seat(seatNumber, 0);
int foundSeat = Collections.binarySearch(seats, requestSeat, null);
if (foundSeat >= 0) {
return seats.get(foundSeat).reserve();
} else {
System.out.println("There is no seat " + seatNumber);
return false;
}
}
// for testing
public Collection<Seat> getSeats() {
return seats;
}
public class Seat implements Comparable<Seat> {
private final String seatNumber;
private double price;
private boolean reserved = false;
public Seat(String seatNumber, double price) {
this.seatNumber = seatNumber;
this.price = price;
}
@Override
public int compareTo(Seat seat) {
// if smaller return < 0, bigger return > 0, equal return 0
return this.seatNumber.compareToIgnoreCase(seat.getSeatNumber());
}
public boolean reserve() {
if (!reserved) {
reserved = true;
System.out.println("Seat " + seatNumber + " reserved.");
return true;
} else {
return false;
}
} public boolean cancel() {
if (reserved) {
reserved = false;
System.out.println("Reservation of seat " + seatNumber + "cancelled");
return true;
} else {
return false;
}
} public String getSeatNumber() {
return seatNumber;
}
public double getPrice() {
return price;
}
}
}

MainTheatre.java 改

import java.util.List;public class MainTheatre {
public static void main(String[] args) {
Theatre theatre = new Theatre("Muzha Guangming", 8, 12);
if (theatre.reserveSeat("D12")) {
System.out.println("Okay, this seat is yours");
} else {
System.out.println("Sorry, this seat is sold out already.");
}
if (theatre.reserveSeat("D12")) {
System.out.println("Okay, this seat is yours");
} else {
System.out.println("Sorry, this seat is sold out already.");
}
if (theatre.reserveSeat("B13")) {
System.out.println("Okay, this seat is yours");
} else {
System.out.println("Sorry, this seat is sold out already.");
}
} public static void printList(List<Theatre.Seat> list) {
for (Theatre.Seat seat : list) {
System.out.print(" " + seat.getSeatNumber() + " " + seat.getPrice());
}
System.out.println();
System.out.println("================================");
}
}

輸出結果:

Seat D12 reserved.

Okay, this seat is yours

Sorry, this seat is sold out already.

There is no seat B13

Sorry, this seat is sold out already.

修改了不少東西

但我不確定這段 Tim 主要想表達啥

比較明顯的是,inner class 裡新增一個 price

在 outer price 則加上了判斷,區隔出不同座位的價格

MainTheatre.java 改

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MainTheatre {
public static void main(String[] args) {
Theatre theatre = new Theatre("Muzha Guangming", 8, 12);
// if (theatre.reserveSeat("D12")) {
// System.out.println("Okay, this seat is yours");
// } else {
// System.out.println("Sorry, this seat is sold out already.");
// }
//
// if (theatre.reserveSeat("D12")) {
// System.out.println("Okay, this seat is yours");
// } else {
// System.out.println("Sorry, this seat is sold out already.");
// }
//
// if (theatre.reserveSeat("B13")) {
// System.out.println("Okay, this seat is yours");
// } else {
// System.out.println("Sorry, this seat is sold out already.");
// }
List<Theatre.Seat> reverseSeats = new ArrayList<>(theatre.getSeats());
Collections.reverse(reverseSeats);
printList(reverseSeats);
} public static void printList(List<Theatre.Seat> list) {
for (Theatre.Seat seat : list) {
System.out.print(seat.getSeatNumber() + ":$" + seat.getPrice()+", ");
}
System.out.println();
System.out.println("================================");
}
}

輸出結果:

H12:$7.0, H11:$7.0, H10:$7.0, H09:$7.0, H08:$7.0, H07:$7.0, H06:$7.0, H05:$7.0, H04:$7.0, H03:$7.0, H02:$7.0, H01:$7.0, G12:$7.0, G11:$7.0, G10:$7.0, G09:$7.0, G08:$7.0, G07:$7.0, G06:$7.0, G05:$7.0, G04:$7.0, G03:$7.0, G02:$7.0, G01:$7.0, F12:$7.0, F11:$7.0, F10:$7.0, F09:$12.0, F08:$12.0, F07:$12.0, F06:$12.0, F05:$12.0, F04:$12.0, F03:$7.0, F02:$7.0, F01:$7.0, E12:$7.0, E11:$7.0, E10:$7.0, E09:$12.0, E08:$12.0, E07:$12.0, E06:$12.0, E05:$12.0, E04:$12.0, E03:$7.0, E02:$7.0, E01:$7.0, D12:$7.0, D11:$7.0, D10:$7.0, D09:$12.0, D08:$12.0, D07:$12.0, D06:$12.0, D05:$12.0, D04:$12.0, D03:$7.0, D02:$7.0, D01:$7.0, C12:$7.0, C11:$7.0, C10:$7.0, C09:$14.0, C08:$14.0, C07:$14.0, C06:$14.0, C05:$14.0, C04:$14.0, C03:$7.0, C02:$7.0, C01:$7.0, B12:$7.0, B11:$7.0, B10:$7.0, B09:$14.0, B08:$14.0, B07:$14.0, B06:$14.0, B05:$14.0, B04:$14.0, B03:$7.0, B02:$7.0, B01:$7.0, A12:$7.0, A11:$7.0, A10:$7.0, A09:$14.0, A08:$14.0, A07:$14.0, A06:$14.0, A05:$14.0, A04:$14.0, A03:$7.0, A02:$7.0, A01:$7.0,

================================

也能倒著輸出座位表跟價格

且不需要多寫逆排序的方法

直接使用 Collections 裡的方法,還滿方便的

Theatre.java 改

import java.util.*;public class Theatre {
private final String theatreName;
private List<Seat> seats = new ArrayList<>();
static final Comparator<Seat> PRICE_ORDER = new Comparator<Seat>() {
@Override
public int compare(Seat seat1, Seat seat2) {
if (seat1.getPrice() < seat2.getPrice()) {
return -1;
} else if (seat1.getPrice() > seat2.getPrice()) {
return 1;
} else {
return 0;
}
}
};
public Theatre(String theatreName, int numRows, int seatsPerRow) {
this.theatreName = theatreName;
int lastRow = 'A' + (numRows - 1);
for (char row = 'A'; row <= lastRow; row++) {
for (int seatNum = 1; seatNum <= seatsPerRow; seatNum++) {
double price = 12.00;
if ((row < 'D') && (seatNum >= 4) && (seatNum <= 9)) {
price = 14.00;
} else if ((row > 'F') || (seatNum < 4) || (seatNum > 9)) {
price = 7.00;
}
Seat seat = new Seat(row + String.format("%02d", seatNum), price);
seats.add(seat);
}
}
}
public String getTheatreName() {
return theatreName;
}
public boolean reserveSeat(String seatNumber) {
Seat requestSeat = new Seat(seatNumber, 0);
int foundSeat = Collections.binarySearch(seats, requestSeat, null);
if (foundSeat >= 0) {
return seats.get(foundSeat).reserve();
} else {
System.out.println("There is no seat " + seatNumber);
return false;
}
}
// for testing
public Collection<Seat> getSeats() {
return seats;
}
public class Seat implements Comparable<Seat> {
private final String seatNumber;
private double price;
private boolean reserved = false;
public Seat(String seatNumber, double price) {
this.seatNumber = seatNumber;
this.price = price;
}
@Override
public int compareTo(Seat seat) {
// if smaller return < 0, bigger return > 0, equal return 0
return this.seatNumber.compareToIgnoreCase(seat.getSeatNumber());
}
public boolean reserve() {
if (!reserved) {
reserved = true;
System.out.println("Seat " + seatNumber + " reserved.");
return true;
} else {
return false;
}
} public boolean cancel() {
if (reserved) {
reserved = false;
System.out.println("Reservation of seat " + seatNumber + "cancelled");
return true;
} else {
return false;
}
} public String getSeatNumber() {
return seatNumber;
}
public double getPrice() {
return price;
}
}
}

MainTheatre.java 改

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MainTheatre {
public static void main(String[] args) {
Theatre theatre = new Theatre("Muzha Guangming", 8, 12);
List<Theatre.Seat> priceSeats = new ArrayList<>(theatre.getSeats());
priceSeats.add(theatre.new Seat("B00", 5));
priceSeats.add(theatre.new Seat("A00", 5));
Collections.sort(priceSeats, Theatre.PRICE_ORDER);
printList(priceSeats);
} public static void printList(List<Theatre.Seat> list) {
for (Theatre.Seat seat : list) {
System.out.print(seat.getSeatNumber() + ":$" + seat.getPrice()+", ");
}
System.out.println();
System.out.println("================================");
}
}

輸出結果:

B00:$5.0, A00:$5.0, A01:$7.0, A02:$7.0, A03:$7.0, A10:$7.0, A11:$7.0, A12:$7.0, B01:$7.0, B02:$7.0, B03:$7.0, B10:$7.0, B11:$7.0, B12:$7.0, C01:$7.0, C02:$7.0, C03:$7.0, C10:$7.0, C11:$7.0, C12:$7.0, D01:$7.0, D02:$7.0, D03:$7.0, D10:$7.0, D11:$7.0, D12:$7.0, E01:$7.0, E02:$7.0, E03:$7.0, E10:$7.0, E11:$7.0, E12:$7.0, F01:$7.0, F02:$7.0, F03:$7.0, F10:$7.0, F11:$7.0, F12:$7.0, G01:$7.0, G02:$7.0, G03:$7.0, G04:$7.0, G05:$7.0, G06:$7.0, G07:$7.0, G08:$7.0, G09:$7.0, G10:$7.0, G11:$7.0, G12:$7.0, H01:$7.0, H02:$7.0, H03:$7.0, H04:$7.0, H05:$7.0, H06:$7.0, H07:$7.0, H08:$7.0, H09:$7.0, H10:$7.0, H11:$7.0, H12:$7.0, D04:$12.0, D05:$12.0, D06:$12.0, D07:$12.0, D08:$12.0, D09:$12.0, E04:$12.0, E05:$12.0, E06:$12.0, E07:$12.0, E08:$12.0, E09:$12.0, F04:$12.0, F05:$12.0, F06:$12.0, F07:$12.0, F08:$12.0, F09:$12.0, A04:$14.0, A05:$14.0, A06:$14.0, A07:$14.0, A08:$14.0, A09:$14.0, B04:$14.0, B05:$14.0, B06:$14.0, B07:$14.0, B08:$14.0, B09:$14.0, C04:$14.0, C05:$14.0, C06:$14.0, C07:$14.0, C08:$14.0, C09:$14.0,

================================

自己設計了一個 compareTo

規則可以隨自己訂

B00 比 A00先,是因為加入的順序,這裡是先加 B00

Theatre.java 改

import java.util.*;public class Theatre {
private final String theatreName;
private List<Seat> seats = new ArrayList<>();
static final Comparator<Seat> PRICE_ORDER; static {
PRICE_ORDER = new Comparator<Seat>() {
@Override
public int compare(Seat seat1, Seat seat2) {
if (seat1.getPrice() < seat2.getPrice()) {
return -1;
} else if (seat1.getPrice() > seat2.getPrice()) {
return 1;
} else {
return 0;
}
}
};
}
public Theatre(String theatreName, int numRows, int seatsPerRow) {
this.theatreName = theatreName;
int lastRow = 'A' + (numRows - 1);
for (char row = 'A'; row <= lastRow; row++) {
for (int seatNum = 1; seatNum <= seatsPerRow; seatNum++) {
double price = 12.00;
if ((row < 'D') && (seatNum >= 4) && (seatNum <= 9)) {
price = 14.00;
} else if ((row > 'F') || (seatNum < 4) || (seatNum > 9)) {
price = 7.00;
}
Seat seat = new Seat(row + String.format("%02d", seatNum), price);
seats.add(seat);
}
}
}
public String getTheatreName() {
return theatreName;
}
public boolean reserveSeat(String seatNumber) {
Seat requestSeat = new Seat(seatNumber, 0);
int foundSeat = Collections.binarySearch(seats, requestSeat, null);
if (foundSeat >= 0) {
return seats.get(foundSeat).reserve();
} else {
System.out.println("There is no seat " + seatNumber);
return false;
}
}
// for testing
public Collection<Seat> getSeats() {
return seats;
}
public class Seat implements Comparable<Seat> {
private final String seatNumber;
private double price;
private boolean reserved = false;
public Seat(String seatNumber, double price) {
this.seatNumber = seatNumber;
this.price = price;
}
@Override
public int compareTo(Seat seat) {
// if smaller return < 0, bigger return > 0, equal return 0
return this.seatNumber.compareToIgnoreCase(seat.getSeatNumber());
}
public boolean reserve() {
if (!reserved) {
reserved = true;
System.out.println("Seat " + seatNumber + " reserved.");
return true;
} else {
return false;
}
} public boolean cancel() {
if (reserved) {
reserved = false;
System.out.println("Reservation of seat " + seatNumber + "cancelled");
return true;
} else {
return false;
}
} public String getSeatNumber() {
return seatNumber;
}
public double getPrice() {
return price;
}
}
}

輸出結果:一樣

他說改成這樣更合理

主要就是修改最上面 Comparator 那邊

在 Intellij 找到那行,左邊有個黃色燈泡

點下 Split into declaration and initialization 即可

Kevin

in order to ensure consistency, the Comparator field here is static final. It is final because we don’t want it to change. It is also static; in case we have more than one Theatre instance, we don’t want different Comparators for each instance.

補充:

Interview Question | Comparable vs Comparator in Java

可以被改寫的 class 就可用 comparable

不能則在外部用 comparator

References to Objects

到底 reference 是啥意思

--

--

張小雄
張小雄

Written by 張小雄

記錄成為軟體工程師的過程

No responses yet