코딩 공부/Java
[Java] 람다식(Lambda)이란?
ballqs
2024. 7. 25. 19:34
자바 8버전으로 넘어오면서 자바로 크게 많이 변경되었다.
예전에 배웠을때랑 크게 차이가 나는게 있는데 Javascript에서 사용했었던 람다식으로 작성이 가능해졌다는 것이다.
그렇게 시대에 맞게 진화했기에 지금의 자바가 된게 아닌가 싶긴 하다.
그러면 람다를 어떻게 사용해나갔는지 살펴보자
람다식이란?
쉽게 말해서 메서드를 "하나의 식"으로 표현한 것이다.
훨씬 간략하게 표현이 가능하게 되며, 메서드의 이름과 반환값이 없어지므로 "익명함수" 라고도 한다.
public class B() {
public boolean flag(int num) {
boolean f = true;
// 내용
return f;
}
}
// 사용할때
B b = new B();
if (b.flag(50)) {
// 내용
} else {
// 내용
}
위의 작성을 람다식으로 표현하게 되면 아래와 같아 진다.
if ((int num) -> {내용에 따른 return}) {
// 내용
}
어떤가? 람다를 사용함으로 코드가 엄청 간결해지지 않았는가?
다만 이렇듯 람다는 장점뿐만이 있는데 아니다.
람다식의 장점
- 코드를 간결하게 만들 수 있다.
- 의도가 보이는 코드의 경우 가독성이 높아진다.
- 작업이 빨라 생산성이 높아진다.
- 병렬 프로그래밍에 용이하다.
람다식의 단점
- 람다를 사용하여 만든 익명함수는 재사용이 불가하다.
- 디버깅이 어렵다.
- 람다를 남발하면 비슷한 함수가 중복 생성되어 가독성이 떨어진다.
- 람다 stream 사용시 for문 혹은 while문 사용시 성능이 떨어진다.
실제로 작성해보면서 이해한 예제
Lambda 클래스
package lambda;
import java.util.ArrayList;
import java.util.List;
public class Lambda {
public static void main(String[] args) {
// 주차 성공 리스트
ArrayList<Car> carsWantToPark = new ArrayList<>();
// 주차할 자동차 리스트
ArrayList<Car> parkingLot = new ArrayList<>();
Car car1 = new Car("Benz", "Class E", true, 0);
Car car2 = new Car("BMW", "Series 7", false, 100);
Car car3 = new Car("BMW", "X9", false, 0);
Car car4 = new Car("Audi", "A7", true, 0);
Car car5 = new Car("Hyundai", "Ionic 6", false, 10000);
carsWantToPark.add(car1);
carsWantToPark.add(car2);
carsWantToPark.add(car3);
carsWantToPark.add(car4);
carsWantToPark.add(car5);
parkingLot.addAll(parkingCarWithTicket(carsWantToPark));
parkingLot.addAll(parkingCarWithMoney(carsWantToPark));
// 리스트 출력
for (Car car : parkingLot) {
System.out.println("Parked Car : " + car.getCompany() + "-" + car.getModel());
}
}
// 티켓여부
public static List<Car> parkingCarWithTicket(List<Car> carsWantToPark) {
ArrayList<Car> cars = new ArrayList<>();
for (Car car : carsWantToPark) {
if (car.hasParkingTicket()) {
cars.add(car);
}
}
return cars;
}
// 티켓없으면 돈이라도 있는지
public static List<Car> parkingCarWithMoney(List<Car> carsWantToPark) {
ArrayList<Car> cars = new ArrayList<>();
for (Car car : carsWantToPark) {
if (!car.hasParkingTicket() && car.getParkingMoney() > 1000) {
cars.add(car);
}
}
return cars;
}
}
Car 클래스!
class Car {
private final String company; // 자동차 회사
private final String model; // 자동차 모델
private final boolean hasParkingTicket;
private final int parkingMoney;
public Car(String company, String model, boolean hasParkingTicket, int parkingMoney) {
this.company = company;
this.model = model;
this.hasParkingTicket = hasParkingTicket;
this.parkingMoney = parkingMoney;
}
// 자동차 회사
public String getCompany() {
return company;
}
// 자동차 모델
public String getModel() {
return model;
}
// 티켓
public boolean hasParkingTicket() {
return hasParkingTicket;
}
// 주차비용
public int getParkingMoney() {
return parkingMoney;
}
}
위 코드에서 한단계 변경을 진행하겠다.
Lambda 클래스
package lambda;
import java.util.ArrayList;
import java.util.List;
public class Lambda {
public static void main(String[] args) {
ArrayList<Car> carsWantToPark = new ArrayList<>();
ArrayList<Car> parkingLot = new ArrayList<>();
Car car1 = new Car("Benz", "Class E", true, 0);
Car car2 = new Car("BMW", "Series 7", false, 100);
Car car3 = new Car("BMW", "X9", false, 0);
Car car4 = new Car("Audi", "A7", true, 0);
Car car5 = new Car("Hyundai", "Ionic 6", false, 10000);
carsWantToPark.add(car1);
carsWantToPark.add(car2);
carsWantToPark.add(car3);
carsWantToPark.add(car4);
carsWantToPark.add(car5);
// Car::함수명 방식
parkingLot.addAll(parkCars(carsWantToPark , Car::hasTicket));
parkingLot.addAll(parkCars(carsWantToPark , Car::noTicketButMoney));
for (Car car : parkingLot) {
System.out.println("Parked Car : " + car.getCompany() + "-" + car.getModel());
}
}
// parkingCarWithTicket 와 parkingCarWithMoney 함수를 하나로 합치기
// 매개 변수에 인터페이스를 받아서 진행하는 방법
public static List<Car> parkCars(List<Car> carsWantToPark, Predicate<Car> function) {
List<Car> cars = new ArrayList<>();
for (Car car : carsWantToPark) {
if (function.flag(car)) {
cars.add(car);
}
}
return cars;
}
}
Car 클래스에 추가
public static boolean hasTicket (Car car) {
return car.hasParkingTicket;
}
public static boolean noTicketButMoney (Car car) {
return !car.hasParkingTicket && car.getParkingMoney() > 1000;
}
Predicate 인터페이스 추가
package lambda;
public interface Predicate<T> {
boolean flag(T t);
}
이미지와 같은 방법으로 동작해서 똑같이 출력이 된다.
람다 방식 적용!
parkingLot.addAll(parkCars(carsWantToPark , (Car car) -> car.hasParkingTicket()));
parkingLot.addAll(parkCars(carsWantToPark , (Car car) -> !car.hasParkingTicket() && car.getParkingMoney() > 1000 ));
Car 클래스에 만들어둔것 조차 사용 안하면서 더 간결하게 사용할수 있게 바뀌었다.
람다식 코드가 더 간결하다는 것을 증명해주는 듯하다.