public class ConcurrentTest {
// 첫 번째 테스트: ConcurrentHashMap 동작 테스트
@Test
public void testConcurrentHashMap() {
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// 데이터를 안전하게 추가
concurrentMap.put("apple", 10);
concurrentMap.put("banana", 20);
// 데이터 읽기 확인
Integer appleCount = concurrentMap.get("apple");
assertEquals(10, appleCount);
assertEquals(20, concurrentMap.get("banana"));
// 동시 접근 중에도 안전한 수정
concurrentMap.compute("apple", (key, value) -> value == null ? 1 : value + 1);
// apple의 값이 11로 변경되어야 함
assertEquals(11, concurrentMap.get("apple"));
}
// 두 번째 테스트: ConcurrentMap 동작 테스트
@Test
public void testConcurrentMap() {
ConcurrentMap<String, String> map = new ConcurrentHashMap<>();
// 값이 없을 때만 추가
map.putIfAbsent("name", "John");
assertEquals("John", map.get("name"));
// 값이 있을 때만 제거
boolean removed = map.remove("name", "John");
assertTrue(removed); // 제거 성공
// 제거 후 값이 null이어야 함
assertNull(map.get("name"));
// 값을 다시 추가
map.put("name", "John");
// 기존 값이 "John"일 때만 "Doe"로 교체
boolean replaced = map.replace("name", "John", "Doe");
assertTrue(replaced); // 교체 성공
// 새로운 값 "Doe" 확인
assertEquals("Doe", map.get("name"));
}
}
public class OptionalTest {
@Test
public void testEmpty() {
// Optional.empty()는 값이 없는 빈 Optional을 생성
Optional<String> emptyOptional = Optional.empty();
// emptyOptional에는 값이 없으므로 isPresent는 false
assertFalse(emptyOptional.isPresent());
// 값이 없으므로 기본값을 반환하는 orElse 사용
String defaultValue = emptyOptional.orElse("Default");
assertEquals("Default", defaultValue);
}
@Test
public void testOf() {
// Optional.of()는 null이 아닌 값을 감싸는 Optional을 생성
Optional<String> optional = Optional.of("Hello");
// 값이 있으므로 isPresent는 true
assertTrue(optional.isPresent());
// 값이 있으므로 그 값을 반환
String value = optional.get();
assertEquals("Hello", value);
}
@Test
public void testOfThrowsExceptionForNull() {
// Optional.of()는 null을 허용하지 않으므로 NullPointerException이 발생해야 함
assertThrows(NullPointerException.class, () -> {
Optional.of(null);
});
}
@Test
public void testOfNullable() {
// Optional.ofNullable()는 값이 null일 수 있는 상황에서 안전하게 Optional을 생성
Optional<String> optionalWithNull = Optional.ofNullable(null);
// 값이 없으므로 isPresent는 false
assertFalse(optionalWithNull.isPresent());
// 값이 null일 경우 대체값을 반환
String defaultValue = optionalWithNull.orElse("Fallback");
assertEquals("Fallback", defaultValue);
}
@Test
public void testIsPresent() {
Optional<Integer> optional = Optional.of(10);
// 값이 있으므로 isPresent는 true
assertTrue(optional.isPresent());
Optional<Integer> emptyOptional = Optional.empty();
// 값이 없으므로 isPresent는 false
assertFalse(emptyOptional.isPresent());
}
@Test
public void testIfPresent() {
Optional<String> optional = Optional.of("Hello");
// 값이 있을 때만 동작 수행 (여기서는 람다식으로 값을 전달받아 출력)
optional.ifPresent(value -> assertEquals("Hello", value));
// 값이 없는 경우는 아무 동작도 하지 않음
Optional<String> emptyOptional = Optional.empty();
emptyOptional.ifPresent(value -> fail("This should not be executed"));
}
@Test
public void testOrElse() {
Optional<String> optionalWithValue = Optional.of("Hello");
// 값이 있으므로 그 값을 반환
String result = optionalWithValue.orElse("Default");
assertEquals("Hello", result);
Optional<String> emptyOptional = Optional.empty();
// 값이 없으므로 대체값을 반환
result = emptyOptional.orElse("Default");
assertEquals("Default", result);
}
@Test
public void testOrElseGet() {
Optional<String> optionalWithValue = Optional.of("Hello");
// 값이 있으므로 그 값을 반환
String result = optionalWithValue.orElseGet(() -> "Fallback");
assertEquals("Hello", result);
Optional<String> emptyOptional = Optional.empty();
// 값이 없으므로 Supplier가 제공한 대체값을 반환
result = emptyOptional.orElseGet(() -> "Fallback");
assertEquals("Fallback", result);
}
@Test
public void testOrElseVsOrElseGet() {
Optional<String> emptyOptional = Optional.empty();
// orElse는 항상 대체값을 계산 (심지어 값이 있더라도)
String result = emptyOptional.orElse("Fallback");
assertEquals("Fallback", result);
// orElseGet은 값이 없을 때만 Supplier를 호출
result = emptyOptional.orElseGet(() -> "Generated");
assertEquals("Generated", result);
}
}
public class SynchronousTest {
@Test
void synchronousTest() {
System.out.println("동기 작업 시작");
String result = performSynchronousTask();
System.out.println("동기 작업 완료");
// 결과가 예상대로 나왔는지 확인
assertEquals("동기 작업 결과", result);
}
// 동기 작업을 수행하는 메서드
private String performSynchronousTask() {
try {
// 2초간 대기하는 동기 작업 시뮬레이션
Thread.sleep(2000);
System.out.println("작업 중...");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "동기 작업 결과";
}
}
public class AsynchronousTest {
@Test
void asynchronousTest() throws ExecutionException, InterruptedException {
System.out.println("비동기 작업 시작");
// 비동기 작업 실행 (논블로킹)
CompletableFuture<String> futureResult = performAsynchronousTask();
System.out.println("다른 작업 수행 중...");
// 비동기 작업이 완료될 때까지 기다리고 결과 확인
String result = futureResult.get(); // `get()`을 사용해 결과를 기다림
System.out.println("비동기 작업 완료");
// 비동기 작업 결과가 예상대로 나왔는지 확인
assertEquals("비동기 작업 결과", result);
}
// 비동기 작업을 수행하는 메서드
private CompletableFuture<String> performAsynchronousTask() {
return CompletableFuture.supplyAsync(() -> {
try {
// 2초간 대기하는 비동기 작업 시뮬레이션
Thread.sleep(2000);
System.out.println("비동기 작업 중...");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "비동기 작업 결과";
});
}
}
@WebServlet(name = "userServlet", urlPatterns = {"/users", "/users/list"})
public class UserServlet extends HttpServlet {
private UsersRepository usersRepository = new UsersRepository();
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String path = req.getServletPath();
System.out.println("path = " + path);
if ("/users/list".equals(path)) {
handleApiList(req, resp);
} else {
handleUserForm(req, resp);
}
}
private void handleUserForm(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 응답의 Content-Type을 설정
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
// 사용자 등록 폼을 HTML 형식으로 작성
PrintWriter out = resp.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>User Registration</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Register New User</h1>");
out.println("<form action='/users' method='post'>");
out.println(" <label for='userId'>User ID:</label><br>");
out.println(" <input type='text' id='userId' name='userId'><br><br>");
out.println(" <label for='userName'>User Name:</label><br>");
out.println(" <input type='text' id='userName' name='userName'><br><br>");
out.println(" <input type='submit' value='Register'>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
private void handleApiList(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 모든 사용자 목록을 JSON 형식으로 반환
List<Users> usersList = usersRepository.findAll();
String result = objectMapper.writeValueAsString(usersList);
// JSON 형식으로 응답
resp.setContentType("application/json");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().println(result);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("UserServlet.doPost");
// 폼 데이터에서 사용자 ID와 이름을 가져옴
String userId = req.getParameter("userId");
String userName = req.getParameter("userName");
// 새로운 사용자 객체를 생성하고 값 설정
Users user = new Users();
user.setUserId(userId);
user.setUserName(userName);
// 사용자 객체를 저장소에 저장
Users savedUser = usersRepository.save(user);
// 응답의 Content-Type을 설정
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
// 저장된 사용자 정보를 포함한 HTML 문서를 생성하고 반환
PrintWriter writer = resp.getWriter();
writer.println("<!DOCTYPE html>");
writer.println("<html>");
writer.println("<head>");
writer.println("<title>User Registered</title>");
writer.println("</head>");
writer.println("<body>");
writer.println("<h1>User Registered Successfully</h1>");
writer.println("<p>User ID: " + savedUser.getUserId() + "</p>");
writer.println("<p>User Name: " + savedUser.getUserName() + "</p>");
writer.println("<a href='/users'>Register another user</a>");
writer.println("</body>");
writer.println("</html>");
}
}
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '3.2.8'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'education'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation 'jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api'
implementation 'org.glassfish.web:jakarta.servlet.jsp.jstl'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
implementation 'jakarta.servlet:jakarta.servlet-api'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
tasks.named('test') {
useJUnitPlatform()
}