Skip to content

Commit c5004a0

Browse files
committed
Initial structure
1 parent 159d5d4 commit c5004a0

File tree

12 files changed

+268
-0
lines changed

12 files changed

+268
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.kunicki.functional_java;
2+
3+
import org.kunicki.functional_java.api.Api;
4+
import org.kunicki.functional_java.domain.Service;
5+
6+
public class Application {
7+
8+
private void start() {
9+
// load config
10+
// create database connection pool
11+
12+
// create repository
13+
final var service = new Service(/* repository */);
14+
final var api = new Api(service);
15+
16+
// HTTP server
17+
// ...
18+
}
19+
20+
// @SpringBootApplication
21+
public static void main(String[] args) {
22+
// SpringApplication.run(Application.class, args);
23+
new Application().start();
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.kunicki.functional_java;
2+
3+
record Person(String name, int age) {
4+
}
5+
6+
interface PersonValidator {
7+
8+
//region Common validation logic
9+
default boolean isNameValid(String name) {
10+
return name.startsWith("M");
11+
}
12+
13+
default boolean isAgeValid(int age) {
14+
return age == 38;
15+
}
16+
//endregion
17+
}
18+
19+
class FailingFast implements PersonValidator {
20+
21+
}
22+
23+
class Accumulating implements PersonValidator {
24+
25+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.kunicki.functional_java.api;
2+
3+
import org.kunicki.functional_java.domain.Service;
4+
5+
public class Api {
6+
7+
private final Service service;
8+
9+
public Api(Service service) {
10+
this.service = service;
11+
}
12+
13+
public Response<?> findUserById(Long id) {
14+
final var user = service.findUserById(id);
15+
return user
16+
.map(Response::ok)
17+
.orElse(Response.notFound());
18+
19+
//region Questions
20+
/*
21+
Q: Can you tell whether the service can respond with expected/business/domain errors?
22+
*/
23+
/*
24+
Q: What happens to those errors?
25+
*/
26+
/*
27+
Q: Are GOTO statements good?
28+
*/
29+
/*
30+
Q: What if we represented expected errors as plain values?
31+
*/
32+
//endregion
33+
}
34+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.kunicki.functional_java.api;
2+
3+
sealed interface Response<T> {
4+
5+
record Ok<T>(T value) implements Response<T> {
6+
}
7+
8+
record NotFound<T>() implements Response<T> {
9+
}
10+
11+
record ServerError(String message) implements Response<String> {
12+
}
13+
14+
//region Factory methods
15+
static <T> Response<T> ok(T value) {
16+
return new Ok<>(value);
17+
}
18+
19+
static <T> Response<T> notFound() {
20+
return new NotFound<>();
21+
}
22+
23+
static Response<String> serverError(String message) {
24+
return new ServerError(message);
25+
}
26+
//endregion
27+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.kunicki.functional_java.common;
2+
3+
public interface Attempt<A> {
4+
5+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.kunicki.functional_java.common;
2+
3+
public sealed interface Or<L, R> {
4+
5+
record Left<L, R>(L value) implements Or<L, R> {
6+
}
7+
8+
record Right<L, R>(R value) implements Or<L, R> {
9+
}
10+
11+
//region Factory methods
12+
static <L, R> Or<L, R> left(L value) {
13+
return new Left<>(value);
14+
}
15+
16+
static <L, B> Or<L, B> right(B value) {
17+
return new Right<>(value);
18+
}
19+
//endregion
20+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.kunicki.functional_java.domain;
2+
3+
class Data {
4+
5+
private Long id;
6+
7+
private String value;
8+
9+
public Data(Long id, String value) {
10+
this.id = id;
11+
this.value = value;
12+
}
13+
14+
public Long getId() {
15+
return id;
16+
}
17+
18+
public void setId(Long id) {
19+
this.id = id;
20+
}
21+
22+
public String getValue() {
23+
return value;
24+
}
25+
26+
public void setValue(String value) {
27+
this.value = value;
28+
}
29+
30+
// equals, hashCode, toString
31+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.kunicki.functional_java.domain;
2+
3+
//region Immutable Data
4+
5+
class ImmutableData {
6+
7+
}
8+
//endregion
9+
10+
//region Record
11+
//endregion
12+
13+
//region Record test
14+
15+
class RecordTest {
16+
17+
public static void main(String[] args) {
18+
19+
}
20+
}
21+
//endregion
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.kunicki.functional_java.domain;
2+
3+
import java.util.Optional;
4+
5+
public class Service {
6+
7+
//region Pure functions
8+
9+
//region Definition
10+
/*
11+
Q: What makes a function pure?
12+
* the output only depends on the inputs
13+
* no side effects
14+
*/
15+
//endregion
16+
17+
long doStuff(final long n, final Data data) {
18+
/*
19+
P: mutates the argument
20+
*/
21+
data.setValue("devoxxpl");
22+
23+
/*
24+
P: interacts with I/O
25+
*/
26+
System.out.println(n);
27+
28+
/*
29+
P: depends on something external
30+
P: the if statement does not have a value
31+
*/
32+
if (System.currentTimeMillis() % 2 == 0) {
33+
return n;
34+
} else {
35+
return n + 1;
36+
}
37+
}
38+
39+
//region Tips
40+
/*
41+
T: Use (immutable) values wherever possible
42+
*/
43+
/*
44+
T: Control the side effects
45+
*/
46+
/*
47+
T: Prefer immutability as a rule of thumb
48+
*/
49+
//endregion
50+
51+
//endregion
52+
53+
//region Error handling
54+
public Optional<User> findUserById(Long id) {
55+
return Optional.of(new User(42L, "Jacek"));
56+
}
57+
58+
//region Tips
59+
/*
60+
T: Return expected errors as plain values
61+
*/
62+
/*
63+
T: Keep a catch-all error handler for truly unexpected errors
64+
*/
65+
//endregion
66+
//endregion
67+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.kunicki.functional_java.domain;
2+
3+
public record User(Long id, String name) {
4+
}

0 commit comments

Comments
 (0)