Post

[Day12] java 기초 (string, class, Lambda, generic)

[Day12] java 기초 (string, class, Lambda, generic)

수업 끝나기 5분전에 갑작스럽게 과제를 받았다 !
어제 팀별로 정한 도메인에서 (예를 들어 ,북쇼핑몰) 첫 화면을 구상하고 최대한 만들어보는거였다.
우리 팀은 구체적인 도메인 없이 단순한 쇼핑몰로 제작을 했어서, 범위가 넓었다.
다른 팀원분은 테일즈런너 옷 쇼핑몰? 같은걸 하신다고 하셔서 나는 최근에 필요했던 동물의 숲 페이지로 제작했다.
동물의 숲에서 화석, 물고기, 곤충 채집해서 너굴 상점으로 가져가면 돈으로 바꿔준다.
그래서 게임 속에서 물건을 팔거나 벼룩 시장이 열릴 때마다 인터넷에 가격 검색해봤던게 생각나서 오로지 내가 쓰기 위해 동물의숲 쇼핑몰로 제작해봤다..ㅎㅎ !

과제 url : https://raccoon-shop.netlify.app/

String/StringBuffer/StringBuilder

String

  • 불변의 객체
  • 문자열 연산 시 새로운 객체를 생성 → 시간복잡도 O(n), 공간복잡도 상승

StringBuffer

  • 가변(Mutable) 객체 (문자열 연산 시 기존 객체를 변경)
  • 스레드 안전(Thread-safe) → 동기화 지원
  • 성능은 상대적으로 느림

StringBuilder

  • 가변(Mutable) 객체
  • 스레드 안전하지 않음 (동기화 미지원) → 단일 스레드 환경에서 사용 권장
  • StringBuffer보다 성능 우수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class StringTest3 {
	public static void main(String[] args) {
		String s1 = new String("java");//시간복잡도 O(n), 공간복잡도 상승
		String s2 = "java"; //시간복잡도 O(1), 공간복잡도 저하

		//문자열 가공 시
		StringBuffer s3 = new StringBuffer("java");//동시성 문제 있을 때 사용
		StringBuilder s4 = new StringBuilder("java");//동시성 문제 없을 때 사용
		
		System.out.println(s1==s2); // false
		System.out.println(s1.toString()); // java
		System.out.println(s2.toString()); // java
		System.out.println(s3.toString()); // java
		System.out.println(s4.toString()); // java
	}
}

❓❔ 멀티스레드 환경 vs 단일 스레드 환경

단일 스레드 환경 (동시성 문제 x)

  • 한 번에 하나의 작업만 수행할 수 있는 환경
  • 순차적으로 코드가 실행된다
  • 동시성 문제가 없음 → 여러 개의 스레드가 공유 데이터를 동시에 수정할 일이 없기 때문
1
2
3
4
5
6
7
8
9
10
11
public class SingleThreadExample {
   public static void main(String[] args) {
       System.out.println("작업 1 시작");
       task(); // 작업 실행
       System.out.println("작업 2 시작");
   }

   public static void task() {
       System.out.println("작업 실행 중...");
   }
}

1️⃣ 작업 1 시작 → 2️⃣ 작업 실행 중… → 3️⃣ 작업 2 시작

멀티스레드 환경

  • 여러 개의 스레드가 동시에 실행될 수 있는 환경
  • 동시성 문제가 없는 경우
    • 각 스레드가 서로 다른 리소스를 사용하거나
    • 단순히 읽기 작업만 수행할 때
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyThread extends Thread {
    private String name;

   public MyThread(String name) {
       this.name = name;
   }

   @Override
   public void run() {
       System.out.println(name + " 스레드 실행 중...");
   }
}

public class MultiThreadExample {
    public static void main(String[] args) {
       MyThread t1 = new MyThread("스레드 1");
       MyThread t2 = new MyThread("스레드 2");

       t1.start(); // 스레드 1 시작
       t2.start(); // 스레드 2 시작
   }
}
// 두 개의 스레드가 동시에 실행되지만, 서로 다른 리소스를 사용하므로 동시성 문제가 없음

Wrapper class

  • 기본 자료형(Primitive Type)을 객체(Object)로 감싸는 클래스
  • 기본 자료형 → 참조형(Reference Type)으로 변환 가능
1
2
3
int num = 10;
Integer obj = Integer.valueOf(num); // 박싱 (Boxing)
int num2 = obj.intValue(); // 언박싱 (Unboxing)
기본 자료형Wrapper 클래스
intInteger
doubleDouble
charCharacter
booleanBoolean

오토박싱(Auto Boxing) / 오토언박싱(Auto Unboxing)

1
2
Integer obj = 10; // 오토박싱
int num = obj; // 오토언박싱

❓❔ 오토박싱(Auto-Boxing) vs 언박싱(Unboxing)

자바에서는 기본 자료형(int, double, char 등)과 래퍼 클래스(Integer, Double, Character 등)를 자동으로 변환하는 기능이 있다.

오토박싱(Auto-Boxing)

기본 자료형 → 래퍼 클래스로 자동 변환하는 과정

1
2
3
4
5
6
7
public class AutoBoxingExample {
    public static void main(String[] args) {
        int num = 10;
        Integer obj = num; // 오토박싱 (int → Integer)
        System.out.println("오토박싱된 값: " + obj);
    }
}

언박싱(Unboxing)

래퍼 클래스 → 기본 자료형으로 자동 변환하는 과정

1
2
3
4
5
6
7
public class UnboxingExample {
   public static void main(String[] args) {
       Integer obj = 20;
       int num = obj; // 언박싱 (Integer → int)
       System.out.println("언박싱된 값: " + num);
   }
}

Inner Class (내부 클래스)

  • 클래스 내부에 또 다른 클래스를 정의하는 방식
  • 코드의 응집도를 높이고 외부 클래스와 긴밀한 관계를 가지도록 도와준다.

1️⃣ 초기 코드 (독립 클래스 사용)

  • MyButtonHandler가 독립적인 클래스로 존재
  • 외부에서 TextField, TextArea를 설정해야 하는 불편함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class Main {
    public static void main(String[] args) {
        Frame f = new Frame();
        Button b1 = new Button("전송1");
        Panel p = new Panel();
        TextField tf = new TextField(25);
        TextArea ta = new TextArea();

        f.add(ta);
        f.add(p, BorderLayout.SOUTH);
        p.add(tf);
        p.add(b1);

        MyButtonHandler btnHandler = new MyButtonHandler();
        btnHandler.setTextField(tf);
        btnHandler.setTextArea(ta);

        b1.addActionListener(btnHandler);
        tf.addActionListener(btnHandler);

        f.setSize(400, 500);
        f.setBackground(Color.GREEN);
        f.setVisible(true);
    }
}

// MyButtonHandler.java (독립 클래스)
package notepad;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class MyButtonHandler implements ActionListener {
    TextField tf;
    TextArea ta;

    public void setTextField(TextField tf) {
        this.tf = tf;
    }

    public void setTextArea(TextArea ta) {
        this.ta = ta;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        ta.append(tf.getText() + "\n");
        tf.setText("");
    }
}

내부 클래스(Inner Class) 적용

  • 내부 클래스로 MyButtonHandler를 포함하여, 불필요한 setTextField, setTextArea 제거
  • MyButtonHandler가 내부 클래스로 포함되어, Main 클래스의 tf, ta를 직접 접근 가능 → 코드 간결화
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Main {
    TextField tf;
    TextArea ta;

    public Main() {
        Frame f = new Frame();
        Button b1 = new Button("전송1");
        Panel p = new Panel();
        tf = new TextField(25);
        ta = new TextArea();

        f.add(ta);
        f.add(p, BorderLayout.SOUTH);
        p.add(tf);
        p.add(b1);

        MyButtonHandler btnHandler = new MyButtonHandler();
        b1.addActionListener(btnHandler);
        tf.addActionListener(btnHandler);

        f.setSize(400, 500);
        f.setBackground(Color.GREEN);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        new Main();
    }

    // 내부 클래스 적용
    public class MyButtonHandler implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            ta.append(tf.getText() + "\n");
            tf.setText("");
        }
    } // inner
} // outer

Anonymous Inner Class(익명 클래스) 적용

  • 익명 내부 클래스로 MyButtonHandler, MyFrameHandler를 대체하여 코드 줄이기
  • 객체를 직접 생성하면서 actionPerformed() 메서드를 재정의
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Main {
    TextField tf;
    TextArea ta;

    public Main() {
        Frame f = new Frame();
        Button b1 = new Button("전송1");
        Panel p = new Panel();
        tf = new TextField(25);
        ta = new TextArea();

        f.add(ta);
        f.add(p, BorderLayout.SOUTH);
        p.add(tf);
        p.add(b1);

        // 익명 내부 클래스 적용 (버튼 핸들러)
        tf.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ta.append(tf.getText() + "\n");
                tf.setText("");
            }
        });

        // 익명 내부 클래스 적용 (창 닫기 핸들러)
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        f.setSize(400, 500);
        f.setBackground(Color.GREEN);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        new Main();
    }
}
  • ✔ 코드 줄이기: 불필요한 클래스 정의 없이 즉시 구현 가능
  • ✔ 가독성 증가: MyButtonHandler와 MyFrameHandler가 하나의 파일에서 처리됨

Lambda (람다식)

  • anonymous class(익명 클래스)의 가독성을 위한 축약 표현
  • 인터페이스의 단일 메서드 구현을 간결하게 표현 가능 (Functional Interface 사용) => 리스트나 배열을 정렬할 때 많이 씁니다. (ex) 우리 알고리즘 문제 풀이 할 때
1
2
3
4
tf.addActionListener(e -> { // 하고 싶은 일
    ta.append(tf.getText() + "\n");
    tf.setText("");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
save_item.addActionListener( e -> {
        // save_item이 클릭 되었을 때 실행되는 영역
        // FileDialog를 열기
        FileDialog save_dialog=new FileDialog(f, "save", FileDialog.SAVE);
        save_dialog.setVisible(true);
        
        try {
            FileWriter fw=new FileWriter(save_dialog.getDirectory()+save_dialog.getFile());
            fw.write(ta.getText());
            fw.close();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }
);

Generics (제네릭)

  • 컴파일 타임에 타입을 체크하여 안정성을 높이고, 캐스팅을 최소화
  • Homogeneous Collection(동일 타입 데이터 저장)의 성능 개선을 위한 기법
1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
	public static void main(String[] args) {
		ArrayList<Integer> list = new ArrayList();//homogeneous collection
		list.add(1);
		list.add(new Integer(2));
		list.add(3);
		
		for (Integer i : list) {// no shadow effect
            System.out.println(i.intValue());
		}
	}
}
컬렉션제네릭 사용 예
ArrayList<T> ArrayList<String> list = new ArrayList<>();
HashMap<K, V>HashMap<Integer, String> map = new HashMap<>();

Comparator

  • 사용자 정의 정렬 기준을 설정할 때 사용
  • 람다식을 이용한 간결한 표현 가능
1
2
3
4
5
6
7
8
9
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(20);
list.add(3);

System.out.println("정렬 전: " + list);

list.sort((o1, o2) -> o1 - o2); // 오름차순 정렬
System.out.println("정렬 후: " + list);

  • ✔ 사실 오늘 메모장 코드를 따라하면서 실행하려니 이런 에러가 떴다.
  • ✔ 알고보니 내가 설치할 때 arm버전이 아니라 x64버전으로 깔았는데 실행이 되길래 냅뒀던게 여기서 터진거였다..
  • ✔ 결국 재설치 엔딩 … 재설치하고 못따라가서 시간을 매우 잡아먹었다. 담엔 버전을 잘 살피자 !

팀스터디

java ui를 이용해 회원가입으로 정보를 입력하고 arraylist에 넣어서 한번에 보여주기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package notepad;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

public class Main  {
	TextField id,name,password;
	TextArea ta;
	
	public Main() {
		Frame f=new Frame();
		Button b1=new Button("가입");
		Button b2=new Button("전체고객 정보보기");
		
		Panel p=new Panel();
		Panel p2=new Panel();
		
		id=new TextField(8);
		name=new TextField(8);
		password=new TextField(8);
		
		ta=new TextArea();
		MenuBar mb=new MenuBar();
		
		f.setMenuBar(mb);
		f.add(ta);
		f.add(p, BorderLayout.SOUTH);
		f.add(p2, BorderLayout.NORTH);
		p.add(id);
		p.add(name);
		p.add(password);
		p.add(b1);		
		p2.add(b2);
		
		ArrayList<String[]> users = new ArrayList<>();
						
		b1.addActionListener(e->{
			 users.add(new String[]{id.getText(),name.getText(),password.getText()});
			 System.out.println(users);
			 id.setText("");
			 name.setText("");
			 password.setText("");
			 ta.setText("");
		});
		
		b2.addActionListener(e->{
			 for (String[] user : users) {
	                ta.append("아이디: " + user[0] + ", 비밀번호: " + user[1] + ", 이름: " + user[2] + "\n");
	            }
			
		});
		
		f.addWindowListener(new WindowAdapter(){			
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);			
			}		
		});
		
		f.setSize(400, 500);
		f.setBackground(Color.GREEN);
		f.setVisible(true);
	}

	public static void main(String[] args) {
		new Main();		
	}	
}

✔ 결과물

This post is licensed under CC BY 4.0 by the author.