자바 8버전을 기점으로 자바의 기능과 문법이 획기적으로 변화했다!
자바 8 버전의 주요 문법
→ 람다 표현식, 스트림 API, Optional
익명 함수 - 함수는 함수이지만 이름이 없는 함수
"자바 기본 문법에서는 함수만 따로 선언할 수 없고 클래스가 있어야 한다."
🧐 클래스를 먼저 선언한 다음 그 안에 함수를 선언해야 그 전체를 메서드라고 부를 수 있다. 클래스와 메서드에 모두 이름을 붙여줘야 하나의 함수로 사용할 수 있었다!!
임시로 사용할 함수 때문에 매번 클래스 선언, 메서드 선언을 해야 하는 것은 상당히 불편한 일이다.
하지만 람다 표현식을 사용하면 코드가 무척이나 간결해진다.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List list = new ArrayList<String>();
list.add("public");
list.add("static");
list.add("void");
// 익명 클래스 코드
list.sort(new Comparator<String>() {
@Override
public int compare(String str1, String str2) {
return str1.compareTo(str2);
}
});
// 람다 표현식 코드
list.sort((Comparator<String>) (str1, str2) -> str1.compareTo(str2));
}
}
var1 -> System.out.println(var1)
System.out.println
은 리턴 값이 void
이기 때문에 이 람다 표현식의 리턴 값도 void
var1 -> {
var1 = var1 + 1;
System.out.println(var1);
return var1;
}
var1
을 return하고 있다고 가정하고 있지만 return문이 없는 경우 람다 표현식의 리턴 값은 void
가 된다(var1, var2) -> System.out.println(var1 + var2)
(var1, var2) -> {
System.out.println(var1);
System.out.println(var2);
}
자바스크립트와 화살표 표기법만 다르군요
컬렉션에 추가된 메서드의 집합
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List list = new ArrayList<String>();
list.add("public");
list.add("static");
list.add("void");
// for 문으로 List 순회
for (int i = 0; i < list.size(); i++ { // list.size()는 리스트의 크기 반환
System.out.println(list.get(i)); // i 번째 요소 출력
}
// for 문을 스트림 API로 바꾸기 => forEach() 메서드 사용
list.stream().forEach(str -> System.out.println(str));
}
}
실행 결과 >
public
static
void
반복문을 위한 변수 i를 알 필요가 없다!
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
Integer[] integerArray = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<Integer> list = Arrays.asList(integerArray);
// java for문
List evenList = new ArrayList<Integer>();
for (int i = 0; i < list.size(); i++) {
Integer number = list.get(i);
if (number % 2 == 0) { // 2로 나눴을 때의 나머지가 0이면 2의 배수다.
evenList.add(number);
}
}
for (int i = 0; i < evenList.size(); i++) {
System.out.println(evenList.get(i));
}
// java 스트림 API
List evenList = list.stream()
.filter(value -> value % 2 == 0).collect(Collectors.toList());
evenList.stream().forEach(value -> System.out.println(value));
}
}
filter()
메서드를 사용하여 코드를 훨씬 간결하게 만들었다.
forEach()
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
Integer[] integerArray = new Integer[]{1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(integerArray);
list.stream().forEach(value -> System.out.println(value));
}
}
컬렉션의 요소들을 하나씩 꺼내어 반복하기 때문에 반복문을 쉽게 대체할 수 있다.
filter()
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
Integer[] integerArray = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<Integer> list = Arrays.asList(integerArray);
List evenList = list.stream()
.filter(value -> value % 2 == 0).collect(Collectors.toList());
evenList.stream().forEach(value -> System.out.println(value));
}
}
컬렉션의 요소들 중 조건문에 맞는 요소만 뽑아 새로운 스트림을 만든다.
distinct()
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
Integer[] integerArray = new Integer[]{1, 1, 1, 1, 2, 2, 2, 3, 3, 4};
List<Integer> list = Arrays.asList(integerArray);
List<Integer> distinctList = list.stream().distinct().toList();
distinctList.stream().forEach(value -> System.out.println(value));
}
}
컬렉션의 요소에서 중복을 제거한다.
중복을 제거한다는 행위가 이미 정해져 있기 때문에 람다 표현식을 함수의 인자로 넣어줄 필요가 없고, 중복인지 아닌지를 판단하는 것은 요소들의 equals()
메서드이다.
map()
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
String[] lowercaseArray = new String[]{"public", "static", "void"};
List<String> lowercaseList = Arrays.asList(lowercaseArray);
List<String> uppercaseList = lowercaseList.stream()
.map(value -> value.toUpperCase()).toList();
uppercaseList.stream().forEach(value -> System.out.println(value));
}
}
컬렉션의 요소들에 특정 연산을 적용한 새로운 스트림을 만든다.
collect()
/toList()
앞서 소개한 메서드들과 함께 .collect(Collectors.toList())
형태로 사용하면 스트림을 간단하게 리스트로 만들 수 있다. 자바 16버전 부터는.toList()
사용해 더욱 간결하게 코드를 작성할 수 있다.
NullPointException을 우아하게 해결하기 위해 등장!
public class Main {
private static String getSomeString() {
return null; // 이 메서드는 항상 null을 반환한다.
}
public static void main(String[] args) {
String isThisNull = getSomeString();
if(null != isThisNull) {
System.out.println(isThisNull.toUpperCase());
}
}
}
이런 식으로 어떤 메서드를 호출했다면 해당 메서드에 null
이 반환되었는지를 반드시 체크해야 한다. 체크하지 않으면 NullPointException이 발생!
이 때 Optional을 사용하면 if 문으로 null
을 체크하는 코드를 다음과 같이 개선할 수 있다.
import java.util.Optional;
public class Main {
private static Optional<String> getSomeString() {
return Optional.empty(); // null을 반환하는 것이 아니라 비어있는 Optional을 반환한다.
}
public static void main(String[] args) {
Optional<String> isThisNull = getSomeString();
isThisNull.ifPresent(str -> System.out.println(str.toUpperCase()));
}
}
Optional로 선언된 메서드에서 반환된 문자열이 비어 있지 않은 경우 ifPresent()
의 인자로 들어간 람다 표현식을 실행하고, 비어있는 경우 실행되지 않는다.
값을 포함한 Optional을 반환하려면 아래와 같이 작성한다.
import java.util.Optional;
public class Main {
private static Optional<String> getSomeString() {
return Optional.ofNullable("public static void");
}
public static void main(String[] args) {
Optional<String> isThisNull = getSomeString();
isThisNull.ifPresent(str -> System.out.println(str.toUpperCase())); // PUBLIC STATIC VOID가 출력된다.
}
}
디자인 패턴이란?
소프트웨어 개발 과정에서 자주 나타나는 문제 해결 방법 중 다른 분야에서도 재사용하기 좋은 코드의 패턴을 모아 이름을 붙인 것.
안티패턴은 이와 반대로 개발 과정에서 자주 나타나지만, 비효율적이거나 생산적이지 않은 패턴을 말한다.
<이것이 백엔드 개발이다 with 자바> 책을 공부하고 정리한 내용입니다.