解读「Java By Comparison - Become a Java Craftsman in 70 Examples」
提高代码可读性
避免反向思考
class Laboratory{
Microscope microscope;
Result analyze(Sample sample){
if (microscope.isInorganic(sample)){
return Result.INORGANIC;
}else{
return analyzeOrganic(sample);
}
}
private Result analyzeOrganic(Sample sample){
if (!microscope.isHumanoid(sample)){
return Result.ALIEN;
}else{
return Result.HUMANOID;
}
}
}
改造后
class Laboratory {
Microscope microscope;
Result analyze(Sample sample) {
if (microscope.isOrganic(sample)) {
return analyzeOrganic(sample);
} else {
return Result.INORGANIC;
}
}
private Result analyzeOrganic(Sample sample) {
if (!microscope.isHumanoid(sample)) {
return Result.HUMANOID;
} else {
return Result.ALIEN;
}
}
}
简化表达式
class SpaceShip {
Crew crew;
FuelTank fuelTank;
Hull hull;
Navigator navigator;
OxygenTank oxygenTank;
boolean willCrewSurvive() {
return hull.holes == 0 &&
fuelTank.fuel >= navigator.requiredFuelToEarth() &&
oxygenTank.lastsFor(crew.size) > navigator.timeToEarth();
}
}
改造后
class SpaceShip {
Crew crew;
FuelTank fuelTank;
Hull hull;
Navigator navigator;
OxygenTank oxygenTank;
boolean willCrewSurvive() {
boolean hasEnoughResources = hasEnoughFuel() && hasEnoughOxygen();
return hull.isIntact() && hasEnoughResources;
}
private boolean hasEnoughOxygen() {
return oxygenTank.lastsFor(crew.size) > navigator.timeToEarth();
}
private boolean hasEnoughFuel() {
return fuelTank.fuel >= navigator.requiredFuelToEarth();
}
}
用空行来区分业务逻辑
enum DistanceUnit {
MILES, KILOMETERS;
static final double MILE_IN_KILOMETERS = 1.60934;
static final int IDENTITY = 1;
static final double KILOMETER_IN_MILES = 1 / MILE_IN_KILOMETERS;
double getConversionRate(DistanceUnit unit) {
if (this == unit) {
return IDENTITY;
}
if (this == MILES && unit == KILOMETERS) {
return MILE_IN_KILOMETERS;
} else {
return KILOMETER_IN_MILES;
}
}
}
改造后
enum DistanceUnit {
MILES, KILOMETERS;
static final double MILE_IN_KILOMETERS = 1.60934;
static final int IDENTITY = 1;
static final double KILOMETER_IN_MILES = 1 / MILE_IN_KILOMETERS;
double getConversionRate(DistanceUnit unit) {
if (this == unit) {
return IDENTITY;
}
if (this == MILES && unit == KILOMETERS) {
return MILE_IN_KILOMETERS;
} else {
return KILOMETER_IN_MILES;
}
}
}
用代码块区分业务逻辑
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
if (user.isUnknown()) {
cruiseControl.logUnauthorizedAccessAttempt();
} else if (user.isAstronaut()) {
cruiseControl.grantAccess(user);
} else if (user.isCommander()) {
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
}
}
}
改造后
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
if (user.isUnknown()) {
cruiseControl.logUnauthorizedAccessAttempt();
return;
}
if (user.isAstronaut()) {
cruiseControl.grantAccess(user);
} else if (user.isCommander()) {
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
}
}
}
用常量替换魔术数字
class CruiseControl {
private double targetSpeedKmh;
void setPreset(int speedPreset) {
if (speedPreset == 2) {
setTargetSpeedKmh(16944);
} else if (speedPreset == 1) {
setTargetSpeedKmh(7667);
} else if (speedPreset == 0) {
setTargetSpeedKmh(0);
}
}
void setTargetSpeedKmh(double speed) {
targetSpeedKmh = speed;
}
}
改造后
class CruiseControl {
static final int STOP_PRESET = 0;
static final int PLANETARY_SPEED_PRESET = 1;
static final int CRUISE_SPEED_PRESET = 2;
static final double CRUISE_SPEED_KMH = 16944;
static final double PLANETARY_SPEED_KMH = 7667;
static final double STOP_SPEED_KMH = 0;
private double targetSpeedKmh;
void setPreset(int speedPreset) {
if (speedPreset == CRUISE_SPEED_PRESET) {
setTargetSpeedKmh(CRUISE_SPEED_KMH);
} else if (speedPreset == PLANETARY_SPEED_PRESET) {
setTargetSpeedKmh(PLANETARY_SPEED_KMH);
} else if (speedPreset == STOP_PRESET) {
setTargetSpeedKmh(STOP_SPEED_KMH);
}
}
void setTargetSpeedKmh(double speed) {
targetSpeedKmh = speed;
}
}
用枚举代替常量
class CruiseControl {
static final int STOP_PRESET = 0;
static final int PLANETARY_SPEED_PRESET = 1;
static final int CRUISE_SPEED_PRESET = 2;
static final double CRUISE_SPEED_KMH = 16944;
static final double PLANETARY_SPEED_KMH = 7667;
static final double STOP_SPEED_KMH = 0;
private double targetSpeedKmh;
void setPreset(int speedPreset) {
if (speedPreset == CRUISE_SPEED_PRESET) {
setTargetSpeedKmh(CRUISE_SPEED_KMH);
} else if (speedPreset == PLANETARY_SPEED_PRESET) {
setTargetSpeedKmh(PLANETARY_SPEED_KMH);
} else if (speedPreset == STOP_PRESET) {
setTargetSpeedKmh(STOP_SPEED_KMH);
}
}
void setTargetSpeedKmh(double speed) {
targetSpeedKmh = speed;
}
}
改造后
class CruiseControl {
private double targetSpeedKmh;
void setPreset(SpeedPreset speedPreset) {
Objects.requireNonNull(speedPreset);
setTargetSpeedKmh(speedPreset.speedKmh);
}
void setTargetSpeedKmh(double speed) {
targetSpeedKmh = speed;
}
}
enum SpeedPreset {
STOP(0), PLANETARY_SPEED(7667), CRUISE_SPEED(16944);
final double speedKmh;
SpeedPreset(double speedKmh) {
this.speedKmh = speedKmh;
}
}
用字符Format取代字符相加
class Mission {
Logbook logbook;
LocalDate start;
void update(String author, String message) {
LocalDate today = LocalDate.now();
String month = String.valueOf(today.getMonthValue());
String formattedMonth = month.length() < 2 ? "0" + month : month; String entry = author.toUpperCase() + ": [" + formattedMonth + "-" +
today.getDayOfMonth() + "-" + today.getYear() + "](Day " + (ChronoUnit.DAYS.between(start, today) + 1) + ")> " + message + System.lineSeparator();
logbook.write(entry);
}
}
改造后
class Mission {
Logbook logbook;
LocalDate start;
void update(String author, String message) {
LocalDate today = LocalDate.now();
String entry = String.format("%S: [%tm-%<te-%<tY](Day %d)> %s%n",
author, today,
ChronoUnit.DAYS.between(start, today) + 1, message);
logbook.write(entry);
}
}
使用Java命名规范
class Rover {
static final double WalkingSpeed = 3;
final String SerialNumber;
double MilesPerHour;
Rover(String NewSerialNumber) {
SerialNumber = NewSerialNumber;
}
void Drive() {
MilesPerHour = WalkingSpeed;
}
void Stop() {
MilesPerHour = 0;
}
}
改造后
class Rover {
static final double WALKING_SPEED = 3;
final String serialNumber;
double milesPerHour;
Rover(String serialNumber) {
serialNumber = serialNumber;
}
void drive() {
milesPerHour = WALKING_SPEED;
}
void stop() {
milesPerHour = 0;
}
}
避免单字母变量
class Inventory {
List<Supply> sl = new ArrayList<>();
boolean isInStock(String n) {
Supply s = new Supply(n); int l=0;
int h = sl.size() - 1;
while (l <= h) {
int m = l + (h - l) / 2;
int c = sl.get(m).compareTo(s);
if (c < 0) {
l = m + 1;
} else if (c>0) {
h = m - 1;
} else {
return true;
}
}
return false;
}
}
改造后
class Inventory {
List<Supply> sortedList = new ArrayList<>();
boolean isInStock(String name) {
Supply supply = new Supply(name);
int low = 0;
int high = sortedList.size() - 1;
while (low <= high) {
int middle=low+(high-low)/2;
int comparison = sortedList.get(middle).compareTo(supply);
if (comparison < 0) {
low = middle + 1;
} else if (comparison > 0) {
high = middle - 1;
} else {
return true;
}
}
}
}
避免缩写
class Logbook {
static final Path DIR = Paths.get("/var/log");
static final Path CSV = DIR.resolve("stats.csv");
static final String GLOB = "*.log";
void createStats() throws IOException {
try (DirectoryStream<Path> dirStr =
Files.newDirectoryStream(DIR, GLOB);
BufferedWriter bufW = Files.newBufferedWriter(CSV)) {
for (Path lFile : dirStr) {
String csvLn = String.format("%s,%d,%s",
lFile,
Files.size(lFile),
Files.getLastModifiedTime(lFile));
bufW.write(csvLn);
bufW.newLine();
}
}
}
}
改造后
class Logbook {
static final Path LOG_FOLDER = Paths.get("/var/log");
static final Path STATISTICS_CSV = LOG_FOLDER.resolve("stats.csv");
static final String FILE_FILTER = "*.log";
void createStatistics() throws IOException {
try (DirectoryStream<Path> logs =
Files.newDirectoryStream(LOG_FOLDER, FILE_FILTER);
BufferedWriter writer =
Files.newBufferedWriter(STATISTICS_CSV)) {
for (Path log : logs) {
String csvLine = String.format("%s,%d,%s",
log,
Files.size(log),
Files.getLastModifiedTime(log));
writer.write(csvLine);
writer.newLine();
}
}
}
}
避免过度命名
class MainSpaceShipManager {
AbstractRocketPropulsionEngine abstractRocketPropulsionEngine;
INavigationController navigationController;
boolean turboEnabledFlag;
void navigateSpaceShipTo(PlanetInfo planetInfo) {
RouteData data = navigationController.calculateRouteData(planetInfo);
LogHelper.logRouteData(data);
abstractRocketPropulsionEngine.invokeTask(data, turboEnabledFlag);
}
}
改造后
class SpaceShip {
Engine engine;
Navigator navigator;
boolean turboEnabled;
void navigateTo(Planet destination) {
Route route = navigator.calculateRouteTo(destination);
Logger.log(route);
engine.follow(route, turboEnabled);
}
}
尽早检查
class CruiseControl {
static final double SPEED_OF_LIGHT_KMH = 1079252850;
static final double SPEED_LIMIT = SPEED_OF_LIGHT_KMH;
private double targetSpeedKmh;
void setTargetSpeedKmh(double speedKmh) {
if (speedKmh < 0) {
throw new IllegalArgumentException();
} else if (speedKmh <= SPEED_LIMIT) {
targetSpeedKmh = speedKmh;
} else {
throw new IllegalArgumentException();
}
}
}
改造后
class CruiseControl {
static final double SPEED_OF_LIGHT_KMH = 1079252850;
static final double SPEED_LIMIT = SPEED_OF_LIGHT_KMH;
private double targetSpeedKmh;
void setTargetSpeedKmh(double speedKmh) {
if (speedKmh < 0 || speedKmh > SPEED_LIMIT) {
throw new IllegalArgumentException();
}
targetSpeedKmh = speedKmh;
}
}
让你的代码更简洁
避免无意义的比较
class Laboratory {
Microscope microscope;
Result analyze(Sample sample) {
if (microscope.isInorganic(sample) == true) {
return Result.INORGANIC;
} else {
return analyzeOrganic(sample);
}
}
private Result analyzeOrganic(Sample sample) {
if (microscope.isHumanoid(sample) == false) {
return Result.ALIEN;
} else {
return Result.HUMANOID;
}
}
}
改造后:
class Laboratory {
Microscope microscope;
Result analyze(Sample sample) {
if (microscope.isInorganic(sample)) {
return Result.INORGANIC;
} else {
return analyzeOrganic(sample);
}
}
private Result analyzeOrganic(Sample sample) {
if (!microscope.isHumanoid(sample)) {
return Result.ALIEN;
} else {
return Result.HUMANOID;
}
}
}
直接返回结果
class Astronaut {
String name;
int missions;
boolean isValid() {
if (missions < 0 || name == null || name.trim().isEmpty()) {
return false;
} else {
return true;
}
}
}
改造后:
class Astronaut {
String name;
int missions;
boolean isValid() {
return missions < 0 || name == null || name.trim().isEmpty());
}
}
用For-Each代替For
class LaunchChecklist {
List checks = Arrays.asList("Cabin Pressure",
"Communication",
"Engine");
Status prepareForTakeoff(Commander commander) {
for (int i = 0; i < checks.size(); i++) {
boolean shouldAbortTakeoff = commander.isFailing(checks.get(i));
if (shouldAbortTakeoff) {
return Status.ABORT_TAKE_OFF;
}
}
return Status.READY_FOR_TAKE_OFF;
}
}
改造后
class LaunchChecklist {
List checks = Arrays.asList("Cabin Pressure",
"Communication",
"Engine");
Status prepareForTakeoff(Commander commander) {
for (String check : checks) {
boolean shouldAbortTakeoff = commander.isFailing(checks);
if (shouldAbortTakeoff) {
return Status.ABORT_TAKE_OFF;
}
}
return Status.READY_FOR_TAKE_OFF;
}
}
更多的使用Java API
class Inventory {
private List<Supply> supplies = new ArrayList<>();
int getQuantity(Supply supply) {
if (supply == null) {
throw new NullPointerException("supply must not be null");
int quantity = 0;
for (Supply supplyInStock : supplies) {
if (supply.equals(supplyInStock)) {
quantity++;
}
}
return quantity;
}
}
改造后
class Inventory {
private List<Supply> supplies = new ArrayList<>();
int getQuantity(Supply supply) {
Objects.requireNonNull(supply, "supply must not be null");
return Collections.frequency(supplies, supply);
}
}
增强代码的健壮性
避免空值异常
class Logbook {
void writeMessage(String message, Path location) throws IOException {
if (Files.isDirectory(location)) {
throw new IllegalArgumentException("The path is invalid!");
}
if (message.trim().equals("") || message == null) {
throw new IllegalArgumentException("The message is invalid!");
}
String entry = LocalDate.now() + ": " + message;
Files.write(location, Collections.singletonList(entry),
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
}
}
改造后
class Logbook {
void writeMessage(String message, Path location) throws IOException {
if (message == null || message.trim().isEmpty()) {
throw new IllegalArgumentException("The message is invalid!");
}
if (location == null || Files.isDirectory(location)) {
throw new IllegalArgumentException("The path is invalid!");
}
String entry = LocalDate.now() + ": " + message;
Files.write(location, Collections.singletonList(entry),
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
}
}
避免switch陷阱
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
switch (user.getRank()) {
case UNKNOWN:
cruiseControl.logUnauthorizedAccessAttempt();
case ASTRONAUT:
cruiseControl.grantAccess(user);
break;
case COMMANDER:
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
break;
}
}
}
改造后
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
switch (user.getRank()) {
case UNKNOWN:
cruiseControl.logUnauthorizedAccessAttempt();
break;
case ASTRONAUT:
cruiseControl.grantAccess(user);
break;
case COMMANDER:
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
break;
}
}
}
注意:这段switch还不够完美,可以考虑加上default来防止最终没有条件匹配的情况,也可以用{}把代码包起来,防止作用域的污染。
永远使用代码块(代码少并不永远代表更好的代码)
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
if (user.isUnknown())
cruiseControl.logUnauthorizedAccessAttempt();
if (user.isAstronaut())
cruiseControl.grantAccess(user);
if (user.isCommander())
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
}
}
改造后
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
if (user.isUnknown()) {
cruiseControl.logUnauthorizedAccessAttempt();
}
if (user.isAstronaut()) {
cruiseControl.grantAccess(user);
}
if (user.isCommander()) {
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
}
}
}
避免ConcurrentModificationException错误
class Inventory {
private List<Supply> supplies = new ArrayList<>();
void disposeContaminatedSupplies() {
for (Supply supply : supplies) {
if (supply.isContaminated()) {
supplies.remove(supply);
}
}
}
}
改造后
class Inventory {
private List<Supply> supplies = new ArrayList<>();
void disposeContaminatedSupplies() {
Iterator<Supply> iterator = supplies.iterator();
while (iterator.hasNext()) {
if (iterator.next().isContaminated()) {
iterator.remove();
}
}
}
}
捕捉特定的异常
class TransmissionParser {
static Transmission parse(String rawMessage) {
if (rawMessage != null && rawMessage.length() != Transmission.MESSAGE_LENGTH) {
throw new IllegalArgumentException("Bad message received!");
}
String rawId = rawMessage.substring(0, Transmission.ID_LENGTH);
String rawContent = rawMessage.substring(Transmission.ID_LENGTH);
try {
int id = Integer.parseInt(rawId);
String content = rawContent.trim();
return new Transmission(id, content);
} catch (Exception e) {
throw new IllegalArgumentException("Bad message received!");
}
}
}
改造后
class TransmissionParser {
static Transmission parse(String rawMessage) {
if (rawMessage != null
&& rawMessage.length() != Transmission.MESSAGE_LENGTH) {
throw new IllegalArgumentException("Bad message received!");
}
String rawId = rawMessage.substring(0, Transmission.ID_LENGTH);
String rawContent = rawMessage.substring(Transmission.ID_LENGTH);
try {
int id = Integer.parseInt(rawId);
String content = rawContent.trim();
return new Transmission(id, content);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Bad message received!");
}
}
}
尽量用不可变代替可变
class Distance {
DistanceUnit unit;
double value;
Distance(DistanceUnit unit, double value) {
this.unit = unit;
this.value = value;
}
static Distance km(double value) {
return new Distance(DistanceUnit.KILOMETERS, value);
}
void add(Distance distance) {
distance.convertTo(unit); value += distance.value;
}
void convertTo(DistanceUnit otherUnit) {
double conversionRate = unit.getConversionRate(otherUnit);
unit = otherUnit;
value = conversionRate * value;
}
}
改造后
class Distance {
final DistanceUnit unit;
final double value;
Distance(DistanceUnit unit, double value) {
this.unit = unit;
this.value = value;
}
Distance add(Distance distance) {
return new Distance(unit, value + distance.convertTo(unit).value);
}
Distance convertTo(DistanceUnit otherUnit) {
double conversionRate = unit.getConversionRate(otherUnit);
return new Distance(otherUnit, conversionRate * value);
}
}
用Optional代替Null
class Communicator {
Connection connectionToEarth;
void establishConnection() {
// used to set connectionToEarth, but may be unreliable
}
Connection getConnectionToEarth() {
return connectionToEarth;
}
}
改造后
class Communicator {
Connection connectionToEarth;
void establishConnection() {
// used to set connectionToEarth, but may be unreliable
}
Optional<Connection> getConnectionToEarth() {
return Optional.ofNullable(connectionToEarth);
}
}
调用示例:
communicationSystem.getConnectionToEarth()
.ifPresent(connection ->
connection.send("Houston, we got a problem!") );
提高代码运行效率
避免在循环中做耗时运算
class Inventory {
private List<Supply> supplies = new ArrayList<>();
List<Supply> find(String regex) {
List<Supply> result = new LinkedList<>();
for (Supply supply : supplies) {
if (Pattern.matches(regex, supply.toString())) {
result.add(supply);
}
}
return result;
}
}
改造后
class Inventory {
private List<Supply> supplies = new ArrayList<>();
List<Supply> find(String regex) {
List<Supply> result = new LinkedList<>();
Pattern pattern = Pattern.compile(regex);
for (Supply supply : supplies) {
if (pattern.matcher(supply.toString()).matches()) {
result.add(supply);
}
}
return result;
}
}
利用Java8的parallel
class Inventory {
List<Supply> supplies;
long countDifferentKinds() {
return supplies.stream()
.sequential() // this can be omitted
.filter(Supply::isUncontaminated)
.map(Supply::getName)
.distinct()
.count();
}
}
改造后
class Inventory {
List<Supply> supplies;
long countDifferentKinds() {
return supplies.stream()
.parallel()
.filter(Supply::isUncontaminated)
.map(Supply::getName)
.distinct()
.count();
}
}
改进代码的注释
避免没有意义的注释
class Inventory {
// Fields (we only have one)
List<Supply>supplies=newArrayList<>(); // The list of supplies.
// Methods
int countContaminatedSupplies() {
// TODO: check if field is already initialized (not null)
int contaminatedCounter = 0; // the counter
// No supplies => no contamination
for (Supply supply : supplies) { // begin FOR
if (supply.isContaminated()) {
contaminatedCounter++; // increment counter!
} // End IF supply is contaminated
} // End FOR
// Returns the number of contaminated supplies.
return contaminatedCounter; // Handle with care!
}
} // End of Inventory class
改造后
class Inventory {
List<Supply>supplies=newArrayList<>();
// Methods
int countContaminatedSupplies() {
if (supplies == null || supplies.isEmpty()) {
// No supplies => no contamination
return 0;
}
int contaminatedCounter = 0;
for (Supply supply : supplies) {
if (supply.isContaminated()) {
contaminatedCounter++;
}
}
return contaminatedCounter;
}
}
移除注释掉的代码
class LaunchChecklist {
List<String> checks = Arrays.asList(
"Cabin Leak",
// "Communication", // Do we actually want to talk to Houston? "Engine",
"Hull",
// "Rover", // We won't need it, I think...
"OxygenTank"
//"Supplies"
);
Status prepareLaunch(Commander commander) {
for (String check : checks) {
boolean shouldAbortTakeoff = commander.isFailing(check);
if (shouldAbortTakeoff) {
//System.out.println("REASON FOR ABORT: " + item);
return Status.ABORT_TAKE_OFF; }
}
return Status.READY_FOR_TAKE_OFF;
}
}
}
改造后
class LaunchChecklist {
List<String> checks = Arrays.asList(
"Cabin Leak",
"Hull",
"OxygenTank"
);
Status prepareLaunch(Commander commander) {
for (String check : checks) {
boolean shouldAbortTakeoff = commander.isFailing(check);
if (shouldAbortTakeoff) {
return Status.ABORT_TAKE_OFF; }
}
return Status.READY_FOR_TAKE_OFF;
}
}
}
用方法代替注释
class FuelSystem {
List<Double> tanks = new ArrayList<>();
int getAverageTankFillingPercent() {
double sum = 0;
for (double tankFilling : tanks) {
sum += tankFilling;
}
double averageFuel = sum / tanks.size();
// round to integer percent
return Math.toIntExact(Math.round(averageFuel * 100));
}
}
改造后
class FuelSystem {
List<Double> tanks = new ArrayList<>();
int getAverageTankFillingPercent() {
double sum = 0;
for (double tankFilling : tanks) {
sum += tankFilling;
}
double averageFuel = sum / tanks.size();
return roundToIntegerPercent(averageFuel);
}
static int roundToIntegerPercent(double value) {
return Math.toIntExact(Math.round(value * 100));
}
}
用文档解释缘由
class Inventory {
private List<Supply> list = new ArrayList<>();
void add(Supply supply) {
list.add(supply);
Collections.sort(list);
}
boolean isInStock(String name) {
// fast implementation
return Collections.binarySearch(list, new Supply(name)) != -1;
}
}
改造后
class Inventory {
// Keep this list sorted. See isInStock().
private List<Supply> list = new ArrayList<>();
void add(Supply supply) {
list.add(supply);
Collections.sort(list);
}
boolean isInStock(String name) {
/*
* In the context of checking availability of supplies by name, * facing severe performance issues with >1000 supplies
* we decided to use the binary search algorithm
* to achieve item retrieval within 1 second,
* accepting that we must keep the supplies sorted.
*/
return Collections.binarySearch(list, new Supply(name)) != -1;
}
}
举例说明
class Supply {
/**
* The code universally identifies a supply. *
* It follows a strict format, beginning with an S (for supply), followed
* by a five digit inventory number. Next comes a backslash that
* separates the country code from the preceding inventory number. This
* country code must be exactly two capital letters standing for one of
* the participating nations (US, EU, RU, CN). After that follows a dot
* and the actual name of the supply in lowercase letters. */
static final Pattern CODE =
Pattern.compile("^S\\d{5}\\\\(US|EU|RU|CN)\\.[a-z]+$");
}
改造后
class Supply {
/**
* The expression universally identifies a supply code. *
* Format: "S<inventory-number>\<COUNTRY-CODE>.<name>" *
* Valid examples: "S12345\US.pasta", "S08342\CN.wrench", * "S88888\EU.laptop", "S12233\RU.brush"
*
* Invalid examples:
* "R12345\RU.fuel"
* "S1234\US.light"
* "S01234\AI.coconut"
* " S88888\EU.laptop "
*/
static final Pattern SUPPLY_CODE =
Pattern.compile("^S\\d{5}\\\\(US|EU|RU|CN)\\.[a-z]+$");
}