Skip to content

Commit ddadb8d

Browse files
committed
Add code examples
1 parent 1ed9154 commit ddadb8d

11 files changed

Lines changed: 393 additions & 0 deletions
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.github.aplotnikov.java_8_misuses.domain;
2+
3+
import lombok.Value;
4+
5+
import java.math.BigDecimal;
6+
7+
@Value
8+
public class Application {
9+
10+
long id;
11+
12+
BigDecimal amount;
13+
14+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.github.aplotnikov.java_8_misuses.domain;
2+
3+
import lombok.Value;
4+
5+
import java.util.Optional;
6+
7+
@Value
8+
public class Client {
9+
10+
long id;
11+
12+
public Loan getLastLoan() {
13+
return null;
14+
}
15+
16+
public Optional<Loan> findLastLoan() {
17+
return Optional.empty();
18+
}
19+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.github.aplotnikov.java_8_misuses.domain;
2+
3+
import lombok.Data;
4+
import lombok.EqualsAndHashCode;
5+
import lombok.NoArgsConstructor;
6+
import lombok.ToString;
7+
import lombok.experimental.FieldDefaults;
8+
9+
import static lombok.AccessLevel.PRIVATE;
10+
11+
@NoArgsConstructor
12+
@ToString
13+
@EqualsAndHashCode
14+
@Data
15+
@FieldDefaults(level = PRIVATE)
16+
public class Loan {
17+
18+
long id;
19+
20+
Application application;
21+
22+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.github.aplotnikov.java_8_misuses.domain;
2+
3+
public interface NotificationService {
4+
void sendSms(Client client);
5+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.github.aplotnikov.java_8_misuses.optional;
2+
3+
import io.github.aplotnikov.java_8_misuses.domain.Client;
4+
import io.github.aplotnikov.java_8_misuses.domain.NotificationService;
5+
import io.github.aplotnikov.java_8_misuses.utils.Annotations.Good;
6+
import io.github.aplotnikov.java_8_misuses.utils.Annotations.Ugly;
7+
8+
import java.util.Optional;
9+
10+
import static java.util.Objects.nonNull;
11+
12+
class InternalOptionalUsage {
13+
14+
@Ugly
15+
class UnclearOptionalDependencyWithCheckForNull {
16+
17+
private NotificationService notificationService;
18+
19+
void process(Client client) {
20+
if (nonNull(notificationService)) {
21+
notificationService.sendSms(client);
22+
}
23+
}
24+
25+
void setNotificationService(NotificationService notificationService) {
26+
this.notificationService = notificationService;
27+
}
28+
}
29+
30+
@Good
31+
class ValidInternalOptionalDependency {
32+
33+
private Optional<NotificationService> optionalNotificationService = Optional.empty();
34+
35+
void process(Client client) {
36+
optionalNotificationService.ifPresent(service -> service.sendSms(client));
37+
}
38+
39+
void setNotificationService(NotificationService notificationService) {
40+
optionalNotificationService = Optional.ofNullable(notificationService);
41+
}
42+
}
43+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package io.github.aplotnikov.java_8_misuses.optional;
2+
3+
import io.github.aplotnikov.java_8_misuses.domain.Client;
4+
import io.github.aplotnikov.java_8_misuses.utils.Annotations.Good;
5+
import io.github.aplotnikov.java_8_misuses.utils.Annotations.Ugly;
6+
import lombok.EqualsAndHashCode;
7+
import lombok.Getter;
8+
import lombok.ToString;
9+
import lombok.experimental.FieldDefaults;
10+
11+
import java.util.List;
12+
import java.util.Optional;
13+
14+
import static java.util.Arrays.asList;
15+
import static java.util.Objects.nonNull;
16+
import static lombok.AccessLevel.PRIVATE;
17+
18+
class OptionalConstructorParameters {
19+
20+
@Ugly
21+
class OptionalLeaksOutsideClass {
22+
23+
List<Email> prepareEmails(Client client) {
24+
Email noAttachment = new Email("First!", "No attachment", Optional.empty());
25+
Email withAttachment = new Email("Second!", "With attachment", Optional.of(new Attachment()));
26+
27+
return asList(noAttachment, withAttachment);
28+
}
29+
30+
@FieldDefaults(makeFinal = true, level = PRIVATE)
31+
@Getter
32+
@ToString
33+
@EqualsAndHashCode
34+
class Email {
35+
String subject;
36+
String body;
37+
Optional<Attachment> attachment;
38+
39+
Email(String subject, String body, Optional<Attachment> attachment) {
40+
this.subject = subject;
41+
this.body = body;
42+
this.attachment = attachment;
43+
}
44+
}
45+
}
46+
47+
@Good
48+
class OverloadedConstructors {
49+
List<Email> prepareEmails(Client client) {
50+
return List.of(
51+
new Email("First!", "No attachment"),
52+
new Email("Second!", "With attachment", new Attachment())
53+
);
54+
}
55+
56+
@FieldDefaults(makeFinal = true, level = PRIVATE)
57+
@Getter
58+
@ToString
59+
@EqualsAndHashCode
60+
class Email {
61+
String subject;
62+
String body;
63+
Attachment attachment;
64+
65+
Email(String subject, String body) {
66+
this(subject, body, null);
67+
}
68+
69+
Email(String subject, String body, Attachment attachment) {
70+
this.subject = subject;
71+
this.body = body;
72+
this.attachment = attachment;
73+
}
74+
75+
boolean hasAttachment() {
76+
return nonNull(attachment);
77+
}
78+
}
79+
}
80+
81+
class Attachment {}
82+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package io.github.aplotnikov.java_8_misuses.optional;
2+
3+
import io.github.aplotnikov.java_8_misuses.domain.Client;
4+
import io.github.aplotnikov.java_8_misuses.domain.Loan;
5+
6+
import java.util.List;
7+
import java.util.Optional;
8+
9+
import static io.github.aplotnikov.java_8_misuses.utils.Annotations.Good;
10+
import static io.github.aplotnikov.java_8_misuses.utils.Annotations.Ugly;
11+
import static java.util.Collections.emptyList;
12+
13+
class OptionalForCollections {
14+
15+
@Ugly
16+
class TooVerbose {
17+
18+
Loan findLastClientLoan(Client client) {
19+
Optional<List<Loan>> loans = findClientLoans(client.getId());
20+
21+
if (loans.isPresent() && !loans.get().isEmpty()) {
22+
return loans.get().get(0);
23+
}
24+
25+
throw new IllegalStateException("No loans were found");
26+
}
27+
28+
private Optional<List<Loan>> findClientLoans(long id) {
29+
//find loans into DB
30+
return Optional.empty();
31+
}
32+
}
33+
34+
@Good
35+
class NiceAndClean {
36+
37+
Loan findLastClientLoan(Client client) {
38+
return findClientLoans(client.getId())
39+
.stream()
40+
.findFirst()
41+
.orElseThrow(() -> new IllegalStateException("No loans were found"));
42+
}
43+
44+
private List<Loan> findClientLoans(long id) {
45+
//find loans into DB
46+
return emptyList();
47+
}
48+
}
49+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package io.github.aplotnikov.java_8_misuses.optional;
2+
3+
import io.github.aplotnikov.java_8_misuses.domain.Client;
4+
import io.github.aplotnikov.java_8_misuses.domain.Loan;
5+
import io.github.aplotnikov.java_8_misuses.utils.Annotations.Good;
6+
import io.github.aplotnikov.java_8_misuses.utils.Annotations.Ugly;
7+
8+
import java.util.concurrent.atomic.AtomicLong;
9+
10+
import static java.util.Optional.ofNullable;
11+
12+
class OptionalOrElse {
13+
14+
class BeforeJava8 {
15+
long findLoanId(Client client) {
16+
return client != null && client.getLastLoan() != null ? client.getLastLoan().getId() : -1L;
17+
}
18+
}
19+
20+
@Ugly
21+
class UsingOptionalIsPresent {
22+
long findLoanId(Client client) {
23+
if (ofNullable(client).isPresent()) {
24+
if (ofNullable(client.getLastLoan()).isPresent()) {
25+
return client.getLastLoan().getId();
26+
}
27+
}
28+
return -1L;
29+
}
30+
}
31+
32+
@Ugly
33+
class UsingIfPresentInSameImperativeWayWithDirtyHackOptionalIsPresent {
34+
long findLoanId(Client givenClient) {
35+
AtomicLong result = new AtomicLong(-1);
36+
37+
ofNullable(givenClient).ifPresent(
38+
client -> client.findLastLoan().ifPresent(
39+
loan -> result.set(loan.getId())
40+
)
41+
);
42+
43+
return result.get();
44+
}
45+
}
46+
47+
@Good
48+
class UsingOrElse {
49+
long findLoanId(Client client) {
50+
return ofNullable(client)
51+
.map(Client::getLastLoan)
52+
.map(Loan::getId)
53+
.orElse(-1L);
54+
}
55+
}
56+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package io.github.aplotnikov.java_8_misuses.optional;
2+
3+
import io.github.aplotnikov.java_8_misuses.domain.Client;
4+
import io.github.aplotnikov.java_8_misuses.domain.Loan;
5+
import io.github.aplotnikov.java_8_misuses.utils.Annotations.Good;
6+
import io.github.aplotnikov.java_8_misuses.utils.Annotations.Ugly;
7+
8+
import java.util.Optional;
9+
10+
class OptionalOrThrow {
11+
12+
@Ugly
13+
class ManualCheckForPresenceToThrowException {
14+
Loan getLoan(Client client) {
15+
if (client.findLastLoan().isPresent()) {
16+
return client.findLastLoan().get();
17+
}
18+
19+
throw new IllegalStateException("Client does not have any loans");
20+
}
21+
22+
private Optional<Loan> findLoan(long id) {
23+
return Optional.empty();
24+
}
25+
26+
void deleteLoan(long id) {
27+
Optional<Loan> loan = findLoan(id);
28+
if (loan.isPresent()) {
29+
delete(loan.get());
30+
}
31+
}
32+
33+
private void delete(Loan loan) {
34+
// delete loan from DB
35+
}
36+
}
37+
38+
@Good
39+
class OrElseThrowUsage {
40+
Loan getLoan(Client client) {
41+
return client.findLastLoan()
42+
.orElseThrow(() -> new IllegalStateException("Client does not have any loans"));
43+
}
44+
45+
void deleteLoan(long id) {
46+
findLoan(id).ifPresent(this::delete);
47+
}
48+
49+
private Optional<Loan> findLoan(long id) {
50+
return Optional.empty();
51+
}
52+
53+
private void delete(Loan loan) {
54+
// delete loan from DB
55+
}
56+
}
57+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.github.aplotnikov.java_8_misuses.optional;
2+
3+
import io.github.aplotnikov.java_8_misuses.domain.Loan;
4+
5+
import java.util.Optional;
6+
7+
import static java.util.Objects.nonNull;
8+
9+
class OptionalOverEngineering {
10+
11+
class NullProtectionOverEngineering {
12+
Loan copy(Loan loan) {
13+
Loan copy = new Loan();
14+
15+
copy.setId(loan.getId());
16+
Optional.ofNullable(loan.getApplication()).ifPresent(copy::setApplication);
17+
18+
return copy;
19+
}
20+
}
21+
22+
class SimpleConditionalCopying {
23+
Loan copy(Loan loan) {
24+
Loan copy = new Loan();
25+
26+
copy.setId(loan.getId());
27+
if (nonNull(loan.getApplication())) {
28+
copy.setApplication(loan.getApplication());
29+
}
30+
31+
return copy;
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)