[Routine] 9 주차 시작!

[Routine] 9 주차 시작!

2023년 3월 13일 부터 3월 19일 까지의 나의 루틴.

#목차

2023-03-13

2023-03-13

  • 오늘도 어김없이 영한 님의 인강을 들으면서 출근하였다.
  • 저번 주 주말 내내 이것이 자바다 공부를 했는데 문득 드는 생각이 너무 정리하면서 공부하려고 해서 늦어지는거 같다는 생각이 들었다.
  • 정말 중요하거나 블로그에 적어야할 거 같은 내용만 적고 무슨 챕터를 진행했는지만 블로그에 적으려 한다.

데이터 입출력

성능 향상 스트림

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;

public class Example {
    BufferedInputStream bis = new BufferedInputStream(/* 바이트 입력 스트림 */);
    BufferedOutputStream bos = new BufferedOutputStream(/* 바이트 출력 스트림 */);

    BufferedReader br = new BufferedReader(/* 문자 입력 스트림 */);
    BufferedWriter bw = new BufferedWriter(/* 문자 출력 스트림 */);
}

Continue with Buffer Commit

import java.io.BufferedReader;
import java.io.FileReader;

public class Example {
    BufferedReader br = new BufferedReader(new FileReader("file path"));
    while (true) {
        String str = br.readLine();  // 파일에서 한 행씩 읽음
        if (str == null) break;     // 더 이상 읽을 행이 없을 경우(파일 끝) while 문 종료
    }
}

Continue with BufferReader Commit

기본 타입 스트림

import java.io.DataInputStream;
import java.io.DataOutputStream;

public class Example {
    DataInputStream dis = new DataInputStream(/* 바이트 입력 스트림 */);
    DataOutputStream dos = new DataOutputStream(/* 바이트 출력 스트림 */);
}

Continue with DataInputOutputStream Commit

프린트 스트림

import java.io.PrintStream;
import java.io.PrintWriter;

public class Example {
    PrintStream ps = new PrintStream(/* 바이트 출력 스트림 */);
    PrintWriter pw = new PrintWriter(/* 문자 출력 스트림 */);
}

Continue with PrintStream Commit

객체 스트림

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Example {
    ObjectInputStream ois = new ObjectInputStream(/* 바이트 입력 스트림 */);
    ObjectOutputStream oos = new ObjectOutputStream(/* 바이트 출력 스트림 */);
    
    // writeObject로 객체를 직렬화
    // oos.writeObject(/* 객체 */);
    
    // readObject로 역직열화
    // 객체타입 변수 = (객체타입) ois.readObject();
}

Continue with ObjectInputOutputStream Commit


2023-03-14

2023-03-14

  • 오늘도 어김없이 영한 님의 인강을 들으면서 출근하였다.
  • 얼른 이것이 자바다를 끝내고 영한님의 인강을 들으면서 코드를 치면서 정리해보고 싶다는 생각이 들었다.

데이터 입출력

성능 향상 스트림

Serializable 인터페이스
  • 자바 직렬화란 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)을 아울러서 이야기한다.
  • 시스템적으로 이야기하자면 JVM(Java Virtual Machine 이하 JVM)의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술과 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태를 같이 이야기한다.
import java.io.Serializable;

public class Example implements Serializable {
    // 직렬화 : 일렬로 늘어선 바이트 데이터 => | field1 | field2 | field3 | field14 |
    public int field1;
    protected int filed2;
    int filed3;
    private int filed4;
    
    public static int filed5;   // 정적 필드는 직려로하에서 제외
    transient int filed6;       // transient로 선언된 필드는 직렬화에서 제외

}
serialVersionUID 필드
  • 직렬화할 때 사용된 클래스와 역직렬화할 때 사용된 클래스는 기본적으로 동일한 클래스여야 한다.
  • 만약 클래스의 이름이 같더라도 클래스의 내용이 다르면 역직렬화에 실패한다.
import java.io.Serializable;

public class Example implements Serializable {
    int filed1;
    int filed2;
}
예) Member 클래스로 생성한 객체를 직렬화하면
오른쪽 Member 클래스로 역직렬화 할 수 없다.
—X—>그 이유는 오른쪽 Member 클래스에는
filed3이 있기 때문이다.
public class Member
   implements Serializable {
   int file1;
   int filed2
}
—X—>public class Member
   implements Serializable {
   int filed1;
   int filed2;
   int filed3;
}
  • 클래스 내용이 다르다 할지라도 직렬화된 필드를 공통으로 포함하고 있다면 역직렬화할 수 있는 방법이 있다.
  • 두 클래스가 동일한 serialVersionUID 상수값을 가지고 있으면 된다.
   
public class Member
   implements Serializable {
   static final long
      derialVersionUID = 1;
   int filed1;
   int filed2;
}
—O—>public class Member
   implements Serializable {
   static final long
      serialVersionUID = 1;
   int filed1;
   int filed2;
   int filed3}

File과 Files 클래스

File 클래스
import java.io.File;

public class Example {
    File file = new File("path");
    
    // max path : /
    File macFile = new File("user/dev/thisisjava/test.txt");
    
    // window path : \\ or /
    File windowFile1 = new File("C:/Temp/file.txt");
    File windowFile2 = new File("C:\\Temp\\file.txt");
    
    // 파일이나 폴더가 존재한다면 true를 리턴
    boolean isExist = file.exists();
}

Continue with File Class Commit

입출력 스트림을 생성할 때 File 객체 활용하기
  • 파일 또는 폴더의 정보를 얻기 위해 File 객체를 단독으로 사용할 수 있지만, 파일입출력 스트림을 생성할 때 경로 정보를 제공할 목적으로 사용되기도 한다.
import java.io.File;
import java.io.FileInputStream;

public class Example {
    // 첫 번째 방법
    FileInputStream fis = new FileInputStream("filepath");
    // 두 번째 방법
    File file = new File("filepath");
    FileInputStream fileFis = new FileInputStream(file); 
}
Files 클래스
  • Files 클래스는 정적 메서드로 구성되어 있고, File 보다 좀 더 많은 기능을 제공한다.
public class Example {
    Path path = Path.get(String first, String... more);

    // 예)
    Path path = Path.get("C:/Temp/dir/file.txt");
    Path path = Path.get("C:/Temp/dir", "file.txt");
    Path path = Path.get("C", "Temp", "dir", "file.txt");

    // 절대 경로와 상대 경로
    Path path = Path.get("dir/file.txt");
    Path path = Path.get("./dir/file.txt"); 
    Path path = Path.get("../dir/file.txt"); 
    
}

Continue with Files Class Commit

네트워크 입출력

네트워크 기초

  • LANLocal Area Network은 가정, 회사, 건물, 특정 여역에 존재하는 컴퓨터를 연결하는 것이다.
  • WANWide Area NetworkLAN을 연결한 것으로, 쉽게 말해 인터넷Internet이다
서버와 클라이언트
  • 서비스를 제공하는 프로그램을 일반적으로 서버Server라고 한다.
  • 서비스를 요청하는 프로그램을 클라이언트Client라고 한다.
  • 인터넷에 두 프로그램이 통신하기 위해서는 먼저 클라이언트가 서비스를 요청하고, 서버는 처리결과를 응답으로 제공해준다.
IP 주소
  • IPInternet Protocol는 컴퓨터의 고유한 주소이다.
  • Mac에서는 ifconfig, Window에서는 ipconfig를 터미널/CMD창에서 검색하게 되면 ip 정보를 볼 수 있다.
  • DNSDomain Name System는 도메인 이름으로, IP를 등록하는 저장소이고, 컴퓨터의 IP 주소를 검색한다.
  • 대중에게 서비스를 제공하는 대부분의 컴퓨터는 다음과 같이 도메인 이름으로 IP를 미리 DNS에 미리 등록해 놓는다.
도메인 이름IP주소
www.naver.com222.122.195.5
  • 웹 브라우전즌 웹 서버와 통신하는 클라이언트로, 상요자가 입력한 도메인 이름으로 DNS에서 IP 주소를 검색해 찾는 다음 웹 서버와 연결해서 웹 페이지를 받는다.

2023-03-15

2023-03-15

  • 오늘도 어김없이 영한 님과…🤩

네트워크 입출력

네트워크 기초

Port 번호
  • Port는 운영체제가 관리하는 서버 프로그램의 연결 번호이다.
  • 서버는 시작할 때 특정 Port 번호에 바인딩 한다.
  • 클라이언트도 서버에서 보낸 정보를 받기 위해서는 Port 번호가 필요한데, 서버와 같이 고정적인 Port 번호에 바인딩하는 것이 아니라 운영체제가 자동으로 부여하는 번호를 사용한다.
  • 이 번호는 클라이언트가 서버로 요청할 때 함게 전송되어 서버가 클라이언트로 데이터를 보낼 때 사용된다.

IP 주소 얻기

  • JavaIP 주소를 java.net 패키지의 InetAddress로 표현한다.
  • InetAddress를 이용하면 로컬 컴퓨터의 IP 주소를 얻을 수 있고, 도메인 이름으로 DNS에서 검색한 후 IP 주소를 가져올 수도 있다.
import java.net.InetAddress;

public class Example {
    // local 컴퓨터의 InetAddress를 얻고 싶을 때
    InetAddress is = InetAddress.getLocalHost();
    
    // 컴퓨터의 도메인 이름을 알고 있다면 두 개의 메서드를 사용하여 InetAddress 객체를 얻을 수 있다.
    InetAddress is = InetAddress.getByName(String domainName);          // 단 하나의 IP 주소를 get
    InetAddress[] iaArr = InetAddress.getAllByName(String domainName);  // 등록된 모든 IP 주소를 배열로 get
    
    // 위 메서드들로부터 얻은 InetAddress 객체에서 IP 주소를 얻고 싶을 때
    String ip = InetAddress.getHostAddress();
}

Continue with IP 주소 얻기 Commit

TCP 네트워킹

  • IP 주소로 프로그램들이 통신할 때는 약속된 데이터 전송 규약이 있다. 이것을 전송용 프로토콜Protocol이라고 부른다.
  • 인터넷 에서 전송용 프로토콜은 TCPTransmission Control ProtocolUDPUser Datagram Protocol가 있다.
  • TCP는 연결형 프로토콜로, 상대방이 연결된 상태에서 데이터를 주고 바는다.
  • TCP는 보낸 데이터가 순서대로 전달되며 손실이 발생하지 않는다.
  • TCP는 웹 브라우저가 웹 서버에 연결할 때 사용되며 이메일 전송, 파일 전송, DB 연동에도 사용된다.
  • JavaTCP 네트워킹을 위해 java.net 패키지에서 ServerSocketSocket 클래스를 제공하고 있다.
  • ServerSocket은 클라이언트의 연결을 수학하는 서버 쪽 클래스이고, Socket은 클라이언트에서 연결 요청할 때와 클라이언트와 서버 양쪽에서 데이터를 주고 받을 대 사용되는 클래스이다.
TCP 서버
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class Example {
    // 50001번의 port에 바인딩
    ServerSocket serverSocket = new ServerSocket(50001);

    // 기본 생성자로 객체를 생서하고 port 바인딩을 위해 bind() 메서드를 호출
    ServerSocket serverSocket = new ServerSocket();
    serverSocket.bind(new

    InetSocketAddress(50001));

    // 서버 컴퓨터에 여러 개의 IP가 할당되어 있을 경우, 특정 IP에서만 서비스를 하고 싶다면
    ServerSocket serverSocket = new ServerSocket();
    serverSocket.bind(new

    InetSocketAddress("xxx.xxx.xxx.xxx",50001));

    // ServerSocket이 생성되었다면 연결 요청을 수락하기 위해 accept() 메서드를 실행
    Socket socket = serverSocket.accept();
    
    // return된 Socket을 통해 연결된 클라이언트의 IP 주소와 Port 번호를 얻고 싶다면
    InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
    String clientIp = isa.getHostName();
    String portNo = isa.getPort();
    
    // 서버를 종료하려면 close()
    serverSocket.close();
}

Continue with TCP 서버 Commit

TCP 클라이언트
  • 클라이언트가 서버에 연결 요청을 하려면 Socket 객체를 생성할 때 생성자 매개값으로 서버 IP 주소와 Port 번호를 제공하면 된다.
  • 로컬 컴퓨터에서 실행하는 서버로 연결 요청을 할 경우에는 IP 주소 대신 localhost를 사용할 수 있다.
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

public class Example {
    Socket socket = new Socket("IP", 50001);

    // IP 주소 대신 도메인 이름을 사용하고 싶다면, DNS에서 IP 주소를 검색할 수 있도록 생성자 매개값으로 InetSocketAddress를 제공
    Socket socket = new Socket(new InetSocketAddress("domainName", 50001));

    // Socket 생성과 동시에 연결 요청을 하지 않고 기본 생성자로 Socket을 생성한 후 connect() 메서드로 연결 요청할 수도 있다.
    Socket socket = new Socket();
    socket.connect(new

    InetSocketAddress("domainName",50001));

    // 연결 요청 시 두 가지 예뵈가 발생할 수 있다.
    // UnknownHostException은 IP 주소가 잘못 표기 되었을 때 발생
    // IOException 제공된 IP와 port 번호로 연결할 수 없을 때 발생
    // 따라서 두 가지 예외 모두 처리해야 한다
    try {
        Socket socket = new Socket("IP", 50001);
    } catch(UnknownHostException e) {
        // IP 표기 방법이 잘못되었을 경우
        e.printStackTrace();
    } catch(IOException e) {
        // IP와 Port로 서버에 연결할 수 없는 경우
        e.printStackTrace();
    }
    
    // 서버와 연결된 후에 클라이언트에서 연결을 끊고 싶다면
    socket.close();
}

Continue with TCP 클라이언트 Commit

입출력 스트림으로 데이터 주고 받기
  • 클라이언트가 연결 요청(connect())을 하고 서버가 연결을 수락(accept())했다면 클라이언트와 서버의 양쪽 Socket 객체로부터 가각 입력 스트림InputStream과 출력 스트림스트림OutputStream을 얻을 수 있다.
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Example {
    Socket socket = new Socket();
    InputStream is = socket.getInputStream();
    OutputStream os = socket.getOutputStream();

    // UTF-8로 인코딩 후 바이트 배열을 얻어내고, write() 메서드로 전송
    String data = "보낼 데이터";
    byte[] bytes = data.getBytes("UTF-8");
    os.write(bytes);
    os.flush();

    // 문자열을 좀 더 간편하게 보내고 싶다면 보조 스트림인 DataOutputStream을 사용
    DataInputStream dos = new DataOutputStream(socket.getOutputStream());
    dos.writeUTF(data);
    dos.flush();
    
    // 받는 데이터가 문자열이라면
    byte[] bytes = new byte[1024];
    int num = is.read(bytes);
    String data = new String(bytes, 0, num, "UTF-8");
    
    // 해당 방법은 상대방이 DataOutputStream으로 문자열을 보낼 때만 가능
    DataInputStream dis = new DataInputStream(socket.getInputStream());
    String data = dis.readUTF();
}

Continue with 입출력 스트림으로 데이터 주고 받기 Commit


2023-03-16

  • 오늘은 병원 외래 진료 때문에 휴가이다~~🥳🥳🥳

데이터 입출력

UDT 네트워킹

  • UDPUser Datagram Protocol는 발신자가 일방적으로 수신자에세 데이터를 보내는 방식.
  • TCP 처럼 연결 요청 및 수락 과정이 없기 때문에 TCP보다 데이터 전송 속도가 상대적으로 빠르다.
  • JavaUDP 네트어킹을 위해 java.net 패키지에서 DatagramSocketDatagramPacket 클래스를 제공하고 있다.
  • DatagramSocket은 발신점과 수신점에 해당하고 DatagramPacket은 주고 받는 데이터에 해당한다.
UDP 서버
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;

public class Example {
    // DatagramSocket 객체 생성과 port 번호 생성자 매개값
    DatagramSocket datagramSocket = new DatagramSocket(50001);

    // UDP 서버는 클라이언트가 보낸 DatagramPacket을 항상 받을 준비를 해야 한다. 이 역할을 하는 메서드가 receive()이다
    DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
    datagramSocket.receive(receivePacket);

    // 수신된 데이터와 바이트 수를 얻는 방법 및 문자열
    byte[] bytes = receivePacket.getData();
    int num = receivePacket.getLength();
    String data = new String(bytes, 0, num, "UTF-8");

    // getSocketAddress() 메서드를 호출하면 정보가 담긴 SocketAddress 객체를 얻을 수 있다.
    SocketAddress socketAddress = receivePacket.getSocketAddress();
    
    // 클라이언트로 보맬 Datagrampacket을 생성할 때 네 번째 매개값으로 사용
    String data = "처리 내용";
    byte[] bytes = data.getBytes("UTF-8");
    DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, socketAddress);
    
    // 클라이언트에 보낼 때
    datagramSocket.send(sendPacket);
    
    // UDP 종료
    datagramSocket.close();
}
UDP 클라이언트
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class Example {
    // 기본생성자
    DatagramSocket datagramSocket = new DatagramSocket();

    // 요청을 보내기 위한 DatagramPacket을 생성
    String data = "요청 데이터";
    byte[] bytes = data.getBytes("UTF-8");
    DatagramPacket sendPacket = new DatagramPacket(
            bytes, bytes.length, new InetSocketAddress("localhost", 50001)
    );
    
    // UDP 서버로 전송
    datagramSocket.send(sendPacket);
    
    // close();
    datagramSocket.close();
}

Continue with UDP 서버/클라이언트 Commit

서버의 동시 요청 처리

TCP EchoServer 동시 요청 처리

Continue with TCP 동시 요청 처리 Commit

UDP NewsServer 동시 요청 처리

Continue with UDP 동시 요청 처리 Commit

JSON 데이터 형식

  • 네트워크 통신에서 가장 많이 사용되는 데이터 형식은 JSON`JavaScript Object Notation이다.
표기code설명
객체 표기{
    "속성명": 속성값,
    "속성명": 속성값,
    ···
}
속성명: 반드시"로 감싸야 함
속성값으로 가능한 것
- "문자열", 숫자, true/false
- 객체{···}
- 배열[···]
객체 표기[항목, 항목, ···]항목으로 가능한 것
- "문자열", 숫자, true/false
- 객체{…}
- 배열[…]
{
  "id": "spring",
  "name": "여름",
  "age": 25,
  "student": true,
  "tel": {
    "home": "02-1234-1234",
    "mobile": "010-1234-1234",
    "skill": [
      "java",
      "spring"
    ]
  }
}

데이터베이스 입출력

JDBC 개요

  • Java는 데이터베이스(DB)와 연결해서 데이터 입출력 작업을 할 수 있도록 JDBCJava Database Connectivity 라이브러리(java.sql 패키지)를 제공한다.

애플리케이션
         V
JDBC(java.sql패키지) 인터페이스
         V
JDBC Driver —> ORACLE DATABASE
JDBC Driver —> MySQL
JDBC Driver —> MariaDB
JDBC Driver —> SQL Server

  • DriverManager : JDBC Driver를 관리하며 DB와 연결해서 Connection 구현 객체를 생성한다.
  • Connection : Statement, PreparedStatement, CallableStatement 구현 객체를 생성하며, 트랜잭션Transaction 처리 및 DB 연결을 끊을 때 사용한다.
  • Statement : SQLDDLData Definition LanguageDMLData Manipulation Language을 실행할 때 사용한다. 주로 변경되지 않은 정적 SQL 문을 실행할 때 사용한다.
  • PreparedStatement : Statement와 동일하게 SQLDDL, DML 문을 실행할 때 사용한다. 차이점은 매개변수화된 SQL 문을 사용할 수 있기 때문에 편리성과 보안성이 좋다. 그래서 Statement보다는 PreparedStatement를 주로 사용한다.
  • CallableStatement : DB에 저장되어 있는 프로시저procedure와 함수function를 호출할 때 사용한다.
  • ResultSet : DB에서 가져온 데이터를 일을 때 사용한다.

프로시저와 함수 호출

  • 프로시저와 함수는 DB에 저장되는 PL/SQL 프로그램이다.
  • 클라이언트 프로그램에서 매개값과 함께 프로시저 또는 함수를 호출하면 DB 내부에서 일련의 SQL 문을 실행하고, 실행 결과를 클라이언트 프로그램으로 돌려주는 역할을 한다.
import java.sql.CallableStatement;
import java.sql.Connection;

public class Example {
    public static void main(String[] args) {
        Connection conn = null;
        // 프로시저를 호출할 경우
        String sql = "{ call 프로시저명(?, ?, ?)}";
        CallableStatement cstmt = conn.prepareCall(sql);
        cstmt.setString(1, "값");                // 프로시저 첫 번째 매개값
        cstmt.setString(2, "값");                // 프로시저 두 번째 매개값
        cstmt.registerOutParameter(3, 리턴타입);    // 세 번째 ?는 OUT값(리턴값)임을 지정

        // 함수를 호출할 경우
        String sql = "{ ? =  call 함수명(?, ?)}";
        CallableStatement cstmt = conn.prepareCall(sql);
        cstmt.registerOutParameter(1, 리턴타입);    // 첫 번째 ?는 리턴값을 지정
        cstmt.setString(2, "값");                // 함수의 두 번째 매개값
        cstmt.setString(3, "값");                // 함수의 세 번째 매개값
        
        // 프로시저 또는 함수를 호출하기 위해
        cstmt.execute();
        
        int result = cstmt.getInt(3);   // 프로시저
        int result = cstmt.getInt(1);   // 함수
        
        // 종료
        cstmt.close();
    }
}

트랜잭션 처리

  • 트랜잭션transaction은 기능 처리의 최소 단위를 말한다.
  • 하나의 기능은 여러 가지 소작업들로 구성된다.
  • 최소 단위라는 것이 이 소작업들을 분리할 수 없으며, 전체를 하나로 본다는 개념이다.
  • 트랜잭션은 소작업들이 모두 성공하거나 실패해야 한다.
// 출금 작업
UPDATE accounts SET balance=balance-이체금액 WHERE ano=출금계좌번호

// 입금 작업
UPDATE accounts SET balance=balance-이체금액 WHERE ano=입금계좌번호

  • 드디어 이것이자바다를 다 읽었다… 🥳🥳🥳
  • 이제 다른거 읽어야징~~

2023-03-17

2023-03-17

2023-03-18

  • 블로그의 미완성 부분들을 모두 주석하였다.
  • 차근차근 기존 포스팅했던 내용들을 다듬어 수정할 계획이다.

2023-03-19

  • 오늘은 여자친구와 만나 여자친구는 일을… 난 개인 공부를 진행하였다.
  • 항상 대중교통을 이용하여 이동할 때는 인강을 듣고 이동하는데, 영한 님의 인강을 들을 때마다 IntelliJ 단축키를 스타크래프트 프로게이머처럼 사용하고 싶다는 생각이 들곤 했다.
  • 그런데 오늘 인프런에 찾아보니까 향로님이 올려주신 IntelliJ에 관한 영상이 있어서 해당 영상을 참고해야겠다는 생각이 들었다.

Reference

Back to [Routine] 8 주차 시작!

Continue with [Routine] 10 주차 시작!

[Programming] 이것이 자바다

[Programming] 이것이 자바다

“읽은 기간 : 2023-01-04 ~ 2023-03-16”

#목차

이것이 자바다

책 정보

  • 제목 : 이것이 자바다
  • 부제 : 교육 현장에서 가장 많이 쓰이는 JAVA 프로그래밍의 기본서
  • 저자 : 신용권
  • 쪽수 : 1008쪽
  • 발행(출시)일자 : 2022년 9월 5일

후기

  • Java 기본기를 배우고 JDK 버전에 따른 문법 추가들을 통해 무엇이 달라졌는지 공부할 수 있었다.
  • 아무래도 오래 걸렸던 이유는 책을 읽고 블로그에 정리하면서 하다보니 조금 오래 걸린듯 하다.

[Routine] 8 주차 시작!

[Routine] 8 주차 시작!

2023년 3월 06일 부터 3월 12일 까지의 나의 루틴.

#목차

2023-03-06

2023-03-06

  • 오늘은 워니 님의 인강을 들으면서 출근하였다.
  • 조만간 이력서를 업데이트해야겠다는 생각이 너무 많이 들게 되었다.

스트림 요소 처리

리소스로부터 스트림 얻기

Base Stream

  • BaseStream에는 모든 스트림에서사용할 수 있는 공통 메서드들이 저의되어 있다.
리턴 타입메서드(매개변수)소스
Stream<T>java.util.Collection.stream()
java.util.Collection.parallelStream()
List 컬렉션
Set 컬렉션
Stream<T>
IntStream
LongStream
DoubleStream
Arrays.stream(T[]),  Stream.of(T[])
Arrays.stream(int[]),  IntStream.of(int[])
Arrays.stream(long[]),  LongStream.of(long[])
Arrays.stream(double[]),  DoubleStream.of(double[])
배열
IntStreamIntStream.range(int, int)
IntStream.rangeClosed(int, int)
int 범위
LongStreamLongStream.range(long, long)
LongStream.rangeClosed(long, long)
long 범위
Stream<Path>Files.list(Path)디렉토리
Stream<String>Files.lines(Path, Charset)텍스트 파일
DoubleStream
IntStream
LongStream
Random.double(...)
Random.ints()
Random.longs()
랜덤 수
컬렉션으로부터 스트림 얻기
  • java.util.Collection 인터페이스는 스트림과 parallelStream() 메서드를 가지고 있기 때문에 자식 인터페이스인 ListSet 인터페이스를 구현한 모든 컬렉션에서 객체 스트림을 얻을 수 있다. Continue with Get Stream from Collection Commit
배열로부터 스트림 얻기
  • java.util.Arrays 클래스를 이용하면 다양한 종류의 배열로부터 스트림을 얻을 수 있다. Continue with Get Stream from Arrays Commit
숫자 범위로부터 스트림 얻기
  • IntStream또는 LongStream의 정적 메서드인 range()rangeClose() 메서드를 이용하면 특정 범위의 정수 스트림을 얻을 수 있다.
  • 첫 번째 매개값은 시작 수이고 두 번째 매개값은 끝 수인데, 끝 수를 포함하지 않으면 range(), 포함하면 rangeClosed()를 사용한다.

Continue with Get Stream from Range of Numbers Commit

파일로부터 스트림 얻기
  • java.nio.file.FilesLines() 메서드를 이용하면 텍스트 파일의 행 단위 스트림을 얻을 수 있다.
  • 이는 텍스트 파일에서 한 행씩 읽고 처리할 때 유용하게 사용 할 수 있다.
# file: "data.txt"
{"pno":1, "name":"상품1", "company":"멋진 회사", "price":2340}
{"pno":2, "name":"상품2", "company":"멋진 회사", "price":392}
{"pno":3, "name":"상품3", "company":"멋진 회사", "price":4309}
{"pno":4, "name":"상품4", "company":"멋진 회사", "price":568}
{"pno":5, "name":"상품5", "company":"멋진 회사", "price":4901}

Continue with Get Stream from Files Commit


  • 오늘 퇴근은 워니 님의 인강을 들으면서 퇴근 하였다.
  • 이번 주에 있을 스터디 발표자료를 얼른 준비해야겠다!

2023-03-07

2023-03-07

  • 오늘도 어김없이 워니 님의 인강을 들으면서 출근하였다. 역시 나 혼자 생각해서 이력서를 작성하는 것 보다 인사 담당자나 혹은 해당 직무에서 오랫동안 일했던 사람들에게 피드백을 받는 것이 중요하구나 라는 생각을 했다.
  • 출근 후 이것이 자바다 한 강의만 듣고 얼른 스터디 자료 준비를 해야겠다~

스트림 요소 처리

요소 걸러내기(필터링)

  • 필터링은 요소를 걸러내는 중간 처리 기능이다.
리턴 타입메서드(매개변수)설명
Stream
IntStream
LongStream
DoubleStream
distinct()-중복 제거
filter(Predicate<T>)
filter(IntPredicate)
filter(LongPredicate)
filter(DoublePredicate)
-조건 필터링
-매개 타입은 요소 타입에 따른 함수형 인터페이스이므로 람다식으로 작성 가능
  • distinct() 메서드는 요소의 중복을 제거한다.
  • 객체 스트림(Stream)일 경우, equals() 메서드의 리턴값이 true이면 동일한 요소로 판단한다.
  • IntStream, LongStream, DoubleStream은 같은 값일 경우 중복을 제거한다.

Distinct

  • filter() 메서드는 매개값으로 주어진 Predicatetrue를 리턴하는 요소만 필터링한다. filter
인터페이스추상메서드설명
Predicate<T>boolean test(T t) | 객체 T`를 조사 
IntPredicateboolean test(int value) | int` 값을 조사 
LongPredicateboolean test(Long value) | long` 값을 조사 
DoublePredicateboolean test(Double value) | double` 값을 조사 
  • 모든 Predicate는 매개값을 조사한 후 boolean을 리턴하는 test() 메서드를 가지고 있다. Predicate
  • Predicate<T>의 람다식 표현
    T -> { ... return true }
    또는
    T -> true   // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
    

Continue with Filter Stream Commit


  • 오늘 퇴근도 어김없이 워니 님의 인강을 들으면서 퇴근하였다.
  • 이번 주 목요일날 스터디가 있어 스터디 자료를 얼른 준비 해야겠다.

2023-03-08

2023-03-08

  • 오늘도 어김없이 워니 님의 인강을 듣고 출근하였다.
  • 인강을 다 들어서 얼른 나의 이력서에 반영해봐야겠다.

스트림 요소 처리

요소 변환(매핑)

  • 매핑mapping은 스트림의 요소를 다른 요소로 변환하는 중간 처리 기능이다.
  • 매핑 메서드는 mapXXX(), asDoubleStream(), asLongStream(), boxed(), flatMapXxx() 등이 있다.
요소를 다른 요소로 변환
  • mapXXX() 메서드는 요소를 다른 요소로 변환한 새로운 스트림을 리턴한다. Original to New Stream
  • mapXXX() 메서드의 종류
리턴 타입메서드(매개변수)요소 -> 번환 요소
Stream<R>map(Function<T, R>)T -> R
IntStream<R>
LongStream<R>
DoubleStream<R>
mapToInt(ToIntFunction<T>)
mapToLong(ToLongFunction<T>)
mapToDouble(ToDoubleFunction<T>)
T -> int
T -> long
T -> double
Stream<U>mapToObj(IntFunction<U>)
mapToObj(LongFunction<U>)
mapToObj(DoubleFunction<U>)
int -> U
long -> U
double -> U
DoubleStream
DoubleStream
IntStream
LongStream
mapToDouble(IntToDoubleFunction)
mapToDouble(LongToDoubleFunction)
mapToInt(DoubleToIntFunction)
mapToLong(DoubleToLongFunction)
int -> double
long -> double
double -> int
double -> long
  • 매개타입인 Function은 함수형 인터페이스로, 다음과 같은 종류가 있다.
인터페이스추상 메서드매개값 -> 리턴값
Function<T, R>R apply(T t)T -> R
IntFunction<R>R apply(int value)int -> R
LongFunction<R>R apply(long value)long -> R
DoubleFunction<R>R apply(double value)double -> R
ToIntFunction<T>int applyAsInt(T value)T -> int
ToLongFunction<T>int applyAsLong(T value)T -> long
ToDoubleFunction<T>int applyAsDouble(T value)T -> double
IntToLongFunction<T>long applyAsLong(int value)int -> long
IntToDoubleFunction<T>double applyAsDouble(int value)int -> double
LongToIntFunction<T>int applyAsInt(long value)long -> int
LongToDoubleFunction<T>double applyAsDouble(long value)long -> double
DoubleToIntFunction<T>int applyAsInt(double value)double -> int
DoubleToLongFunction<T>long applyAsLong(double value)double -> long
  • 모든 Function은 매개값을 리턴값으로 매핑(변환)하는 applyXxx() 메서드를 갖고 있다.

Apply Method

  • Function<T, R>을 람다식으로 표현하면 다음과 같다
    T -> { ... return R; }
    또는
    T -> R; // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
    

Continue with Convert Score Stream Commit

  • 기본 타입간의 변환이거나 기본 타입 요소를 래퍼wrapper 객체 요소로 변환하려면 다음과 같은 간편화 메서드를 사용할 수 있다.
리턴 타입메서드(매개변수)설명
LongStreamasLongStream()int -> long
DoubleStreamasLongStream()int -> double
long -> double
Stream<Integer>
Stram<Long>
Stream<Double>
boxed()int -> Integer
long -> Long
double -> Double

Continue with Convert Stream Wrapper Commit


  • 오늘은 퇴근을 여자친구와 만나서 저녁을 먹고 퇴근하였다. 그리고 집에 데려다주고 집에 와서 스터디 발표 준비를 하는데 이번 주는 자료조사가 좀 더 길어질 거 같아 기존에 있는 블로그 내용을 토대로 발표할 예정이다.

2023-03-09 스터디 발표

2023-03-09

  • 늦잠을 자버렸다…😅
  • 요새 자료 준비나 공부로 인해 몸이 많이 피곤에 쌓인 듯하다.
  • 그래서 오늘은 e-sports 경기 하이라이트를 보면서 출근하였다.😙

스트림 요소 처리

요소 변환(매핑)

요소를 복수 개의 요소로 변환
  • flatMapXxx() 메서드는 하나의 요소를 복수 개의 요소들로 변환한 새로운 스트림을 리턴한다.

Convert Multiple Elements

리턴 타입메서드(매개변수)요소 -> 변환 요소
Stream<R>flatMap(Function<T, Stream<R>>)T -> Stream<R>
DoubleStreamflatMap(DoubleFunction<DoubleStream>)double -> DoubleStream
IntStreamflatMap(IntFunction<IntStream>)int -> IntStream
LongStreamflatMap(LongFunction<IntStream>)long -> LongStream
LongStreamflatMap(LongFunction<IntStream>)long -> LongStream
DoubleStreamflatMapToDouble(Function<T, DoubleStream>)T -> DoubleStream
IntStreamflatMapToInt(Function<T, IntStream>)T -> InputStream
LongStreamflatMapToLong(Function<T, LongStream>)T -> LongStream

Continue with Convert Multiple Elements Commit


스터디 발표

  1. 코드는 지우개로 지우게 - 인터페이스

  2. asd - 컬레션 프레임워크

  3. 승연씨 - 네트워크 기초

스터디 발표를 하고 느낀점

  • 스터디를 준비하는 과정과 발표를 하는 과정에서 느낀 점이 나의 포스팅 실력이 형편없는 듯하다는 것을 많이 느꼈다.
  • 조금 더 정확하고 짜임새 있는 글을 작성하고 싶다는 생각을 하게 되었다.
  • 원래 osi 7 layer에서 physical layer를 발표하려고 했는데 생각보다 양이 많고, 확인하고 싶은 것이 생겨 이번에는 기존에 올렸던 [JS] Javascript는 싱글 스레드(Single Threaded)인데 어떻게 병렬처리(다중처리)가 가능할까?를 발표하였는데, 작년에 준비한 블로그 내용이었는데 많이 아쉽다는 생각이 들었다.
  • 꼭 새로운 글이 아닌 기존 글을 조금 더 다듬어서 좋은 내용의 글을 만들고 싶다는 생각이 들어 양보단 질이 중요하다는 것을 느끼게 해준 스터디였다.
  • 당분간 블로그 글에 대해 좀 더 방향성을 생각해 보고 다듬는 기간을 가져야겠다.🧐

2023-03-10

2023-03-10

  • 오늘은 오랜만에 영한 님의 인강을 들으면서 출근하였다.

스트림 요소 처리

요소 정렬

  • 정렬은 요소를 오름차순 또는 내림차순으로 정렬하는 중간 처리 기능이다.
리턴 타입메소드(매개변수)설명
Stream<T>sorted()Comparable 요소를 정렬한 새로운 스트림 생성
Stream<T>sorted(Comparator<T>)요소를 Comparable에 따라 정렬한 새 스트림 생성
DoubleStreamsorted()double 요소를 올림차순으로 정렬
IntStreamsorted()int 요소를 올림차순으로 정렬
LongStreamsorted()long 요소를 올림차순으로 정렬
Comparable 구현 객체의 정렬
  • 스트림의 요소가 객체일 경우 객체가 Comparable을 구현하고 있어야만 sorted() 메서드를 사용하여 정렬할 수 있다.
  • 그렇지 않다면 ClassCastException이 발생한다.
  
public class Xxx implements Comparable {
   ...
}
List<Xxx> list = new ArrayList<>();
Stream<Xxx> stream =list.stream();
Stream<Xxx> orderedStream = stream.sorted();
  • 만약 내림차순으로 정렬하고 싶다면 다음과 같이 Comparator.reverseOrder() 메서드가 리턴하는 Comparator를 매개값으로 제공하면 된다.
public class ComparatorReverseOrder {
    Stream<Xxx> reverseOrderStream = stream.sorted(Comparator.reverseOrder());
}

Continue with Comparable 구현 객체의 정렬 Commit

Comparator를 이용한 정렬
  • 요소 객체가 Comparable을 구현하고 있지 않다면, 비교자를 제공하면 요소를 정렬시킬 수 있다.
  • 비교자는 Comparator 인터페이스를 구현한 객체를 말한다.
sorted((o1, o2) -> { ... })
  • 중괄호 안에는 o1o2보다 작으면 음수, 같으면 0, 크면 양수를 리턴하도록 작성하면 된다.
  • o1o2가 정수일 경우에는 Integer.compare(o1, o2)를, 실수일 경우에는 Double.compare(o1, o2)를 호출해서 리턴값을 리턴해도 좋다.

Continue with Comparator를 이용한 정렬 Commit

요소를 하나씩 처리(루핑)

  • 루핑looping은 스트림에서 요소를 하나씩 반복해서 가져와 처리하는 것을 말한다.
리턴 타입메서드(매개변수)설명
Stream<T>
IntStream
DoubleStream
peek(Consumer<? super T>)
peek(IntComsumer action)
peek(DoubleConsumer acrion)
T반복
int반복
double반복
voidforEach(Consumer<? super T> action)
forEach(IntComsumer action)
forEach(DoubleConsumer acrion)
T반복
int반복
double반복
  • peek()forEach()는 동일하게 요소를 루핑하지만 peek()은 중간 처리 메서드이고, forEach() 메서드는 최종 처리 메서드이다.
  • 따라서 peek()는 최송 처리가 뒤에 붙지 않으면 동작하지 않는다.
인터페이스명추상 메서드설명
Consumer<T>void accept(T t)매개값 T를 받아 소비
IntConsumer<T>void accept(int values)매개값 int를 받아 소비
LongConsumer<T>void accept(long values)매개값 long를 받아 소비
DoubleConsumer<T>void accept(double values)매개값 double를 받아 소비
  • Consumer<? supter T>를 람다식으로 펴한하면 다음과 같다
T -> { ... }
또는
T -> 실행문;   // 하나의 실행문만 있을 경우 중괄호 생략

Continue with 요소를 하나씩 처리(루핑) Commit

요소 조건 만족 여부(매칭)

  • 매칭은 요소들이 특정 조건에 만족하는지 여부를 조사하는 최종 처리 기능이다.
리턴 타입메서드(매개변수)조사 내용
booleanallMatch(Predicate<T> predicate)allMatch(IntPredicate<T> predicate)
allMatch(LongPredicate<T> predicate)
allMatch(DoublePredicate<T> predicate)
모든 요소가 만족하는지 여부
booleananyMatch(Predicate<T> predicate)
anyMatch(IntPredicate<T> predicate)
anyMatch(LongPredicate<T> predicate)
anyMatch(DoublePredicate<T> predicate)
최소한 하나의 요소가 만족하는지
booleannoneMatch(Predicate<T> predicate)
noneMatch(IntPredicate<T> predicate)
noneMatch(LongPredicate<T> predicate)
noneMatch(DoublePredicate<T> predicate)
모든 요소가 만족하지 않는지 여부
  • allMatch(), anyMatch(), noneMatch() 메서드는 매개값으로 주어진 Predicate가 리턴하는 값에 따라 true 또는 false를 리턴한다.

Continue with 요소 조건 만족 여부(매칭) Commit

요소 기본 집계

  • 집계Aggregate는 최종 처리 기능으로 요소들을 처리해서 카운팅, 합계, 평균값, 최대값, 최소값등과 같이 하나의 값으로 산출하는 것을 말한다.
  • 즉, 대량의 데이터를 가공해서 하나의 값으로 축소하는 리덕션Reduction이라고 볼 수 있다.
스트림이 제공하는 기본 집계
  • 스트림은 카운팅, 최대, 최소, 평균, 합계 등을 처리하는 메서드를 제공한다.
리턴타입메서드(매개변수)설명
longcount()요소 개수
OptionalXxxfindFirst()첫 번째 요소
Optional<T>
OptionalXXX
max(Comparator<T>)
max()
최대 요소
Optional<T>
OptionalXXX
min(Comparator<T>)
min()
최소 요소
OptionalDoubleaverage()요소 평균
int, long, doublesum()요소 총합
  • 집계 메서드가 리턴하는 OptionalXXXOptional, OptionalDouble, OptionalInt, OptionalLong 클래스를 말한다.
  • 이들은 최종값을 저장하는 객체로 get(), getAsDouble(), getAsInt(), getAsLong()을 호출하면 최종값을 얻을 수 있다.

Continue with 스트림이 제공하는 기본 집계 Commit


  • 퇴근 후 밥먹고 씻고 잠깐 쉰다는게 일찍 자버렸다…😭

2023-03-11


스트림 요소 처리

요소 기본 집계

Optional 클래스
  • Optinal, OptionalDouble, OptinalInt, OptinalLong 클래슨는 단순히 집계값만 저장하는 것이 아니라ㅡ 집계값이 존재하지 않을 경우 디폴트 값을 설정하거나 집계값을 처리하는 Consumer를 등록할 수 있다.
리턴 타입메서드(매개변수)설명
booleanisPresent()집계값이 있는지 여부
T
double
int
long
orElse(T)
orElse(double)
orElse(int)
orElse(long)
집계값이 없을 경우 디폴트 값 설정
voidifPresent(Consumer)
ifPresent(DoubleConsumer)
ifPresent(IntConsumer)
ifPresent(LongConsumer)
집계값이 있을 경우 Consumer에서 처리
  • 컬렉션의 요소는 동적으로 추가되는 경우가 많다.
  • 만약 컬렉션에 요소가 존재하지 않으면 집계 값을 산출할 수 없으므로 NoSuchElementException 예외가 발생한다.
  • 하지만 앞의 표에 언급되어 있는 메서드를 이용하면 예외 발생을 막을 수 있다.
1) isPresent() 메서드가 true를 리턴할 때만 집계값을 얻는다
import java.util.OptionalDouble;

public class IsPresentTrue {
    public static void main(String[] args) {
        OptionalDouble optional = stream.average();
        if (optional.isPresent()) {
            System.out.println("평균 : " + optional.getAsDouble());
        } else {
            System.out.println("평균 : 0.0");
        }
    }
}
2) orElse() 메서드로 집계값이 없을 경우를 대비해서 디폴트 값을 정해놓는다
public class IsPresentTrue {
    public static void main(String[] args) {
        double avg = stream
                .average()
                .orElse(0.0);
        System.out.println("평균 : " + avg);
    }
}
3) ifPresent() 메서드로 집계값이 있을 경우에만 동작하는 Consumer 람다식을 제공한다
public class IsPresentTrue {
    public static void main(String[] args) {
        stream
                .average()
                .ifPresent(a -> System.out.println("평균 : " + a));
    }
}

Continue with Optional 클래스 Commit

요소 커스텀 집계

  • 스트림은 기본 집계 메서드인 sum(), average(), count(), max(), main()을 제공하지만, 다양한 집계 결과물을 만들 수 있도록 reduce() 메서드도 제공한다.
인터페이스리턴 타입메서드(매개변수)
StreamOptional<T>
T
reduxe(BinaryOperator<T> accumulator)
reduce(T identity, BinaryOperator<T> accumulator)
IntStreamOptionalInt
int
reduxe(IntBinaryOperator op)
reduce(int identity, IntBinaryOperator op)
LongStreamOptionalLong
long
reduxe(LongBinaryOperator op)
reduce(long identity, LongBinaryOperator op)
DoubleStreamOptionalDouble
double
reduxe(DoubleBinaryOperator op)
reduce(double identity, DoubleBinaryOperator op)
  • 매개값인 BinaryOperator는 함수형 인터페이스이다.
  • BinaryOperator는 두 개의 매개값을 받아 하나의 값을 리턴하는 apply() 메서드를 가지고 있기 때문에 다음과 같이 람다식을 작성할 수 있다.
(a, b) -> { ... return 값; }
또는
(a, b) -> 값 // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
  • reduce()는 스트림에 요소가 없을 경우 예외가 발생하지만, identity 매개값이 주어지면 이 값을 default 값으로 리턴한다.
NoSuchElementExceptiondefault 값(identity)인 0 리턴
int sum = stream
   .reduce((a, b) -> a + b)
   .getAsInt();
int sum = stream.reduce(0, (a, b) -> a + b);

Continue with 요소 커스텀 집계 Commit

요소 수집

  • 스트림은 요소들을 필터링 또는 매핑한 후 요소들을 수집하는 최종 처리 메서드인 collect()를 제공한다.
  • 이 메서드를 이용하면 필요한 요소만 컬렉션에 담을 수 있고, 요소들을 그룹핑한 후에 집계도 할 수 있다.
필터링한 요소 수집
  • Streamcollect(Collector<T, A, R> collector) 메서드는 필터링 또는 매핑된 요소들을 새로운 컬렉션에 수집하고, 이 컬렉션을 리턴한다.
  • 매개값인 Collector는 어떤 요소를 어떤 컬렉션에 수집할 것인지를 결정한다.
리턴 타입메서드(매개변수)인터페이스
Rcollect(Collector<T, A, R> collectorStream
  • 타입 파라미터의 T는 요소, A는 누적기accumulator, R은 요소가 저장될 컬렉션이다.
  • 즉, T 요소를 A 누적기가 R에 저장한다는 의미이다.
<div style="width:250px">리턴 타입</div><div style="width:250px">메서드</div>설명
Collector<T, ?, List<T>>toList()TList에 저장
Collector<T, ?, Set<T>>toSet()TSet에 저장
Collector<T, ?, Map<K, U>>toMap(
   Function<T, K> keyMapper,
   Function<T, U> valueMapper
)
TKU로 매핑하여 K를 키로, U를 값으로 Map에 저장
  • 리턴값인 Collector를 보면 A(누적기accumulator)가 ?로 되어 있는데, 이것은 CollectorList, Set, Map 컬렉션에 요소를 저장하는 방법을 알고 있어 별도의 누적기가 필요 없기 때문이다.
  • 아래 코드는 Student 스트림에서 남학생만 필터링해서 별도의 List로 생성하는 코드
//file: "Student 스트림에서 남학생만 필터링해서 별도의 List로 생성하는 코드.java"
import java.util.Collections;

public class Example {
    // Student 스트림에서 남학생만 필터링해서 별도의 List로 생성하는 코드
    List<Student> maleList = totalList.stream()
            .filter(s -> s.getSex().equals("남"))    // 남학생만 필터링
            .collect(Collections.toList());
}
//file: "Student 스트림에서 이름을 키로, 점수를 값으로 갖는 Map 컬렉션을 생성하는 코드.java"
import java.util.Map;
import java.util.stream.Collectors;

public class Example {
    // Student 스트림에서 이름을 키로, 점수를 값으로 갖는 Map 컬렉션을 생성하는 코드
    Map<String, Integer> map = totalList.stream()
            .collect(
                    Collectors.toMap(
                            s -> s.getName(),   // Student 객체에서 키가 될 부분 리턴
                            s -> s.getScore()   // Student 객체에서 값이 될 부분 리턴
                    )
            );
}
  • Java 16 부터 좀 더 편리하게 요소 스트림에서 List 컬렉션을 얻을 수 있다.
  • 스트림에서 바로 toList() 메서드를 다음과 같이 사용하면 된다.
//file: "Java 16부터 스트림에서 List 컬렉션을 얻는 방법.java"

public class Example {
    // Java 16부터 스트림에서 List 컬렉션을 얻는 방법
    List<Student> maleList = totalList.stream()
            .filter(s -> s.getSex().equals("남"))
            .toList();  // <-------------- Java 16부터 스트림에서 List 컬렉션을 쉽게 얻는 방법
    
}

Continue with 요소 수집 Commit

요소 그룹핑
  • collect() 메서드는 단순히 요소를 수집하는 기능 이외에 컬렉션의 요소들을 그룹핑해서 Map 객체를 생성하는 기능도 제공한다.
  • Collectors.groupingBy() 메서드에서 얻은 Collectorcollect() 메서드를 호출할 때 제공한다.
리턴 타입메서드
Collector<T, ?, Map<k, List<T>>>groupingBy(Function<T, K> classifier)
  • groupingBy()Function을 이용해서 TK로 매핑하고, K를 키로 해 List<T>를 값으로 갖는 Map 컬렉션을 생성한다.
//file: "'남', '녀'를 키로 설정하고 List<Student>를 값으로 갖는 Map을 생성하는 코드.java"
import java.util.Map;
import java.util.stream.Collectors;

public class Example {
    // '남', '녀'를 키로 설정하고 List<Student>를 값으로 갖는 Map을 생성하는 코드
    Map<String, List<Student>> map = totalList.stream()
            .collect(
                    Collectors.groupingBy(s -> s.getSex())  // 그룹핑 키 리턴
            );
}

Continue with 요소 그룹핑 return key Commit

  • Collectors.groupingBy() 메서드는 구룹핑 후 매핑 및 집계(평균, 카운팅, 연결, 퇴대, 최소, 합계)를 수행할 수 있도록 두 번째 매개값인 Collector를 가질 수 있다.
  • 다음은 두 번째 매개값으로 사용될 Collector를 얻을 수 있는 Collectors의 정적 메서드들이다.
리턴 타입메서드(매개변수)설명
Collectormapping(Function, Collector)매핑
CollectoraveragingDouble(ToDoubleFunction)평균값
Collectorcouting()요소 수
CollectormaxBy(Comparator)최대 값
CollectorminBy(Comparator)최소 값
Collectorreducing(BynaryOperator<T>)
reducing(T identity, BinaryOperator<T>)
커스텀 집계 값
//file: "학생들을 성별로 그풉핑하고 각각의 평균 점수를 구해서 Map으로 얻는 코드.java"
import java.util.Map;
import java.util.stream.Collectors;

public class Example {
    Map<String, Double> map = totalList.stream()
            .collect(
                    Collectors.groupingBy(
                            s -> s.getSex(),
                            Collectors.averagingDouble(s -> s.getScore)
                    )
            );
}

Continue with 요소 그룹핑 return Map Commit

요소 병렬 처리

  • 요소 병럴 처리Parallel Operation란 멀티 코어 CPU 환경에서 전체 요소를 분할해서 각각의 코어가 병렬적으로 처리하는 것을 말한다.
  • 요소 병렬 처리의 목적은 작업 처리 시간을 줄이는 것에 있다.
  • 자바는 요소 병렬 처리를 위해 병렬 스트림을 제공한다.
동시성과 병렬성
  • 멀티 스레드는 동시성Concurrency 또는 병렬성Parallelism으로 실행되기 때문에 이를 용어에 대해 정확히 이해하는 것이 좋다.
  • 동시성은 멀티 작업을 위해 멀티 스레드가 하나의 코어에서 번갈아 가며 실행하는 것을 말하고, 병렬성은 멀티 작업을 위해 멀티 코어를 각각 이용해서 병렬로 실행하는 것을 말한다.

Concurrency Parallelism

  • 동시성은 한 시점에 하나의 작업만 실행한다.
  • 번갈아 작업을 실행하는 것이 워낙 빠르다 보니 동시에 처리되는 것처럼 보일 뿐이다.
  • 병렬성은 한 시점에서 여러 개의 작업을 병렬로다 실행하기 때문에 동시성보다 좋은 성능을 낸다.
  • 병렬성은 데이터 병렬성Dara parallelism과 작업 병렬성Task parallelism으로 구분할 수 있다.
데이터 병렬성
  • 데이터 병렬성은 전체 데이터를 분할해서 서브 데이터셋으로 만들고 이 서브 데이터셋들을 병렬 처리해서 작업을 빨리 끝내는 것을 말한다.
  • Java 병렬 스트림은 데이터 병렬성을 구현한 것이다.
작업 병렬성
  • 작업 병렬성은 서로 다른 작업을 병렬 처리하는 것을 말한다.
  • 작업 병렬성의 대표적인 예는 서버 프로그램이다.
  • 서버는 각각의 클라이언트에서 요청한 내용을 개별 스레드에서 병렬로 처리한다.
포크조인 프레임워크
  • Java 병렬 스트림은 요소들을 병렬 처리하기 위해 포크조인 프레임워크Forkjoin Framework를 사용한다,
  • 프로조인 프레임워크는 포그 단계에서 전체 요소를 서브 요소셋으로 분발하고, 각각의 서브 요소셋을 멀티 코어에서 병렬로 처리한다.
  • 조인 단계에서 서브 결과를 결합해서 최종 결과를 만들어낸다.
  • 예를들어 쿼드 코어 CPU에서 병렬 스트림으로 요소들을 처리할 경우 먼저 포크 단계에서 스트림의 전체 요소들을 4개의 서브 요소셋으로 분발한다.
  • 그리고 각각의 서브 요소셋을 개별 코어에서 처리하고, 조인 단계에서는 3번의 결합 과정을 거쳐 최종 결과를 산출한다.

Forkjoin Framwork

  • 병렬 처리 스트림은 포크 단계에서 요소를 순서대로 분할하지 않는다.
  • 이해하기 쉽도록 위 그림에서는 앞에서부터 차례대로 4등분 했지만, 내부적으로 요소들을 나누는 알고리즘이 있기 때문에 개발자는 신경 쓸 필요가 없다.
  • 포크조인 프레임워크는 병렬 처리를 위해 스레드풀을 사용한다.
  • 각각의 코어에서 서브 요소셋을 처리하는 것은 작업 스레드가 해야 하므로 스레드 관리가 필요하다.
  • 포크조인 프레임워크는 ExceutorService의 구현 객체인 ForkJoinPool을 사용해서 작업 스레드를 관리한다.

Thread Pool

병렬 스트림 사용
  • Java 병렬 스트림을 이용할 경우에는 백그라운드에서 포크조인 프레임워크가 사용되기 때문에 개발자는 매우 쉽게 병렬 처리를 할 수 있다.
리턴 타입메서드제공 컬렉션 또는 스트림
StreamparallelStream()List 또는 Set 컬렉션
Stream
IntStream
LongStream
DoubleStream
parallel()java.util.Stream
java.util.IntStream
java.util.LongStream
java.util.DoubleStream
  • parallelStream() 메서드는 컬렉션(List, Set)으로부터 병렬 스트림을 바로 리턴한다.
  • parallel() 메서드는 기존 스트림을 병렬 처리 스트림으로 변환한다.
  • 다음 예제는 1억 개의 점수에 대한 평균을 얻을 때 일반 스트림과 병렬 스트림의 처리 시간을 측정한 것이다.
  • 실행 결과를 보면 병렬 스트림에서 요소 처리 시간이 더 빠른 것을 볼 수 있다.
  • 총 3번의 실행을 해보았는데 대략 2배 이상의 실행 속도 차이를 보인다.

Continue with 병렬 스트림 Commit

병렬 처리 성능
  • 스트림 병렬 처리가 스트림 순차 처리보다 항상 실행 성능이 좋다고 판단해서는 안 된다.
  • 그전에 먼저 병렬 처리에 영향을 미치는 다음 3가지 요인을 잘 살펴보아야 한다.
요소의 수와 요소당 처리 시간
  • 컬렉션에 전체 요소의 수가 적고 요소당 처리 시간이 짧으면 일반 스트림이 병렬 스트림보다 빠를 수 있다.
  • 병렬 처리는 포크 및 조인 단계가 있고, 스레드 풀을 생성하는 추가적인 비용이 발생하기 때문이다.
스트림 소스의 종류
  • ArraysList와 배열은 인덱스로 요소를 관리하기 때문에 포크 단계에서 요소를 쉽게 분리할 수 있어 병렬 처리 시간이 절약된다.
  • 반면 HashSet, TreeSet은 요소 분리가 쉽지 않고, LinkedList 역시 링크를 따라가야 하므로 요소 분리가 쉽지 않다.
  • 따라서 이 소스들은 상대적으로 병렬 처리가 늦다.
코어(Core)의 수
  • CPU 코어의 수가 많으면 많을수록 병렬 스트림의 성능은 좋아진다.
  • 하지만 코어의 수가 적을 경우에는 일반 스트림이 더 빠를 수 있다.
  • 병렬 스트림은 스레드 수가 증가하여 동시성이 많이 일어나므로 오히려 느려진다.

2023-03-12


데이터 입출력

입출력 스트림

  • 데이터는 키보드를 통해 입력될 수도 있고, 파일 또는프로그램으로부터 입력될 수도 있다.
  • 반대로 데이터는 모니터로 출력될 수도 있고, 파일에 저장되거나 다른 프로그램으로 전송될 수 있다.
  • 이것을 총칭해서 데이터 입출력이라고 한다.
  • Java는 입력 스트림과 출력 스트림을 통해 데이터를 입출력한다.
  • 스트림Stream은 단방향으로 데이터가 흐르는 것을 말하는데, 다음 그림과 같이 데이터는 출발지에서 나와 도착지로 흘러 들어간다.

Input Output Stream

  • 프로그램을 기준으로 데이터가 들어오면 입력 스트림, 데이터가 나가면 출력 스트림이 된다.
  • 프로그램이 다른 프로그램과 데이터를 교환하려면 양쪽 모두 입력 스트림과 출력 스트림이 필요하다.

Program Input Output Stream

  • 어떤 데이터를 입출력하느냐에 따라 스트림은 다음 두 종류로 구분할 수 있다.

    바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용
    문자 스트림 : 문자만 입출력할 때 사용

  • Java는 데이터 입출력과 관련된 라이브러리를 java.io 패키지에서 제공하고 있다.
  • java.io 패키지는 바이트 스트림과 문자 스트림을 다음과 같이 이름으로 구분해서 제공한다.
구분바이트 스트림문자 스트림
입력 스트림출력 스트림입력 스트림출력 스트림
최상위 클래스InputStreamOutputStreamReaderWriter
하위 클래스
(예)
XXXInputStream
FileInputStream
XXXOutputStream
FileOutputStream
XXXReader
FileReader
XXXWriter
FileWriter
  • 바이트 입출력 스트림의 최상위 클래스는 InputStreamOutputStream이다.
  • 이 클래스를 상속받는 자식 클래스에는 접미사로 InputStream 또는 OutputStream이 붙는다.
  • 예를 들어 이미지와 같은 바이너리 파일의 입출력 스트림 클래스는 FileInputStreamFileOutputStream이다.
  • 문자 입출력 스트림의 최상위 클래스는 ReaderWriter이다.
  • 이 클래스를 상속받는 하위 클래스에는 접미사로 Reader 또는 Writer가 붙는다.
  • 예를 들어 텍스트 파일의 입출력 스트림 클래스는 FileReaderFileWriter이다.

File Input Output Stream

바이트 출력 스트림

  • OutputStream은 바이트 출력 스트림의 최상위 클래스로 추상 클래스이다.
  • 모든 바이트 출력 스트림 클래스는 이 OutputStream 클래스를 상속받아서 만들어진다.

Output Node

  • OutputStream 클래스에는 모든 바이트 출력 스트림이 기본적으로 가져야 할 메서드가 정의되어있다.
리턴 타입메서드설명
voidwrite(int b)1byte를 출력
voidwrite(byte[] b)매개값으로 주어진 배열 b의 모든 바이트를 출력
voidwrite(byte[] b, int off, int len)매개값으로 주어진 배열 b[off]부터 len개의 바이트를 출력
voidclose()출력 스트림을 닫고 사용 메모리 해제
1바이트 출력
  • write(int b) 메서드는 매개값 int(4byte)에서 끝 1byte만 출력한다.
  • 매개변수가 int 타입이므로 4byte 모두를 보내는 것은 아니다.

Output Byte

Continue with 1바이트 출력 Commit

  • FileOutputStream 생성자는 주어진 파일을 생성할 수 없으면 IOException을 발생시킨다.
  • write(), flush(), close() 메서드도 IOException이 발생할 수 있으므로 예외 처리를 해야한다.
  • OutputStream은 내부에 작은 버퍼buffer를 가지고 있다.
  • write() 메서드가 호출되면 버퍼에 바이트를 우선 저장하고, 버퍼가 차면 순서대로 바이트를 출력한다.
  • flush() 메서드는 내부 버퍼에 잔류하는 모든 바이트를 출력하고 버퍼를 비우는 역할을 한다.
  • 내부 버퍼를 사용하는 이유는 출력 성능을 향상하기 위해서이다.
  • 출력 스트림을 더 이상 사용하지 않을 때에는 close() 메서드를 호출해서 출력 스트림이 사용했던 메모리를 해제하는 것이 좋다.
바이트 배열 출력
  • 일반적으로 1byte를 출력하는 경우는 드물고, 보통 바이트 배열을 통째로 출력하는 경우가 많다.
  • write(byte[] b) 메서드는 매개값으로 주어진 배열의 모든 바이트를 출력한다.

Output Byte Array

Continue with 바이트 배열 출력 Commit

바이트 입력 스트림

  • InputStream은 바이트 입력 스트림의 최상위 클래스로, 추상 클래스이다.
  • 모든 바이트 입력 스트림은 InputStream 클래스를 상속받아 만들어진다.

Input Node

  • InputStream 클래스에는 바이트 입력 스트림이 기본적으로 가져야 할 메서드가 정의되어 있다.
리턴 타입메서드설명
intread()1byte를 읽은 후 읽은 바이트를 리턴
intread(byte[] b)읽은 바이트를 매개값으로 주어진 배열에 저장 후 읽은 바이트 수를 리턴
voidclose()입력 스트림을 닫고 상요 메모리 해제
1바이트 읽기
  • read() 메서드는 입력 스트림으로부터 1byte를 읽고 int(4byte) 타입으로 리턴한다.
  • 따라서 리턴된 4byte1byte에만 데이터가 들어 있다.
  • 예를 들어 입력 스트림에서 5개의 바이트가 들어온 다면 다음과 같이 read() 메서드로 1byte씩 5번 읽을 수 있다.

Input Read

  • 더이상 입력 스트림으로부터 바이트를 읽을 수 없다면 read() 메서드는 -1을 리턴하는데, 이것을 이용하면 읽을 수 있는 마지막 바이트까지 반복해서 한 바이트씩 읽을 수 있다.
import java.io.InputStream;

public class Example {
    InputStream is = ...;
    while (true) {
        int data = is.read();   // 1 바이트를 읽고 리턴
        if (data == -1) break;  // -1을 리턴했을 경우 while 문 종료
    }
}

Continue with 1바이트 읽기 Commit

  • FileInputStream 생성자는 주어진 파일이 존재하지 않을 경우 FileNotFoundException을 발생시킨다.
  • 그리고 read(), close() 메서드에서 IOException이 발생할 수 있으므로 두 가지 예외를 모두 처리 해야한다.
바이트 배열로 읽기
  • read(byte[] b) 메서드는 입력 스트림으로부터 주어진 배열의 길이만큼 바이트를 읽고 배열에 저장한 다음 읽은 바이트 수를 리턴한다.
  • 예를 들어 입력 스트림에 5개의 바이트가 들어오면 다음과 같이 길이 3인 배열로 두 번 읽을 수 있다.

Input Read Array

  • read(byte[] b) 역시 입력 스트림으로부터 바이트를 더 이상 읽을 수 없다면 -1을 리턴하는데, 이것을 이용하면 읽을 수 있는 마지막 바이트까지 반복해서 읽을 수 있다.
import java.io.InputStream;

public class Example {
    InputStream is = ...;
    byte[] data = new byte[100];
    while (true) {
        int num = is.read(data);    // 최대 100byte를 읽고, 읽은 바이트는 배열 data 저장, 읽은 수는 리턴
        if (num == -1) break;       // -1을 리턴하면 while 문 종료
    }
}
  • 많은 양의 바이트를 읽을 때는 read(byte[] b) 메서드를 사용하는 것이 좋다.
  • 입력 스트림으로부터 100개의 바이트가 들어온다면 read() 메서드는 100번을 반복해서 읽어야 하지만, read(byte[] b) 메서드는 한 번 읽을 때 배열 길이만큼 읽기 때문에 읽는 횟수가 현저히 줄어든다.

Continue with 1바이트 읽기 Commit

Continue with 파일 복사 Commit

문자 입출력 스트림

  • 바이트 입출력 스트림인 InputStreamOutputStream에 대응하는 문자 입출력 스트림으로 ReaderWriter가 있다.
  • 입출력 되는 단위가 문자인 것을 제외하고는 바이트 입출력 스트림과 사용 방법은 동일하다.
문자 출력
  • Writer는 문자 출력 스트림의 최상위 클래스로, 추상 클래스이다.
  • 모든 문자 출력 스트림 클래스는 Writer 클래스를 상속받아서 만들어진다.

Writer

  • Writer 클래스는 모든 문자 출력 스트림이 기본적으로 가져야 할 메서드가 정의되어 있다.
리턴 타입메서드설명
voidwrite(int c)매개값으로 주어진 한 문자를 출력
voidwrite(char[] cbuf)매개값으로 주어진 배열의 모든 문자를 출력
voidwrite(char[] cbuf, int off, int len)매개값으로 주어진 배열에서 cbuf[off]부터 len까지의 문자를 출력
voidwrite(String str)매개값으로 주어진 문자열을 출력
voidwrite(String str, int off, int len)매개값으로 주어진 문자열에서 off 순번부터 len개까지의 문자를 출력
voidflush()버퍼에 잔류하는 모든 문자를 출력
voidclose()출력 스트림을 닫고 사용 메모리를 해제
  • WriterOutputStream과 사용방법은 동일하지만, 출력 단위가 문자(char)이다.
  • 문자열을 출력하는 write(String str) 메서드를 추가로 제공한다.

Continue with 문자 출력 Commit

문자 읽기
  • Reader는 문자 입력 스트림의 최상위 클래스고, 추상 클래스이다.
  • 모든 문자 입력 스트림 클래스는 Reader 클래스를 상속받아서 만들어진다.

Reader

  • Reader 클래스에는 문자 입력 스트림이 기본적으로 가져야 할 메서드가 저으이되어 있다.
리턴 타입메서드설명
intread()1개의 문자를 읽고 리턴
intread(char[] cbuf)읽은 문자들을 매개값으로 주어진 문자 배열에 저장하고 읽은 문자 수를 리턴
voidclose()입력 스트림을 닫고, 사용 메모리 해제
  • ReaderInputStream과 사용 방법은 동일하지만, 출력 단위가 문자(char)이다.

Continue with 문자 읽기 Commit

보조 스트림

  • 보조 스트림이란 다른 스츠림과 연결되어 여러 가지 편리한 기능을 제공해주는 스트림을 말한다.
  • 보조 스트림은 자체적으로 입출력을 수행할 수 없기 때문에 입출력 소스로부터 직접 생성된 입출력 스트림에 연결해서 사용해야 한다.

Secondary Stream

  • 입출력 스트림에 보조 스트림을 연결하려면 보조 스트림을 생성할 때 생성자 매개값으로 입출력 스트림을 제공하면 된다.
  • 보조스트림 변수 = new 보조스트림(입출력스트림);
  • 예를 들어 바이트 입력 스트림인 FileInputStreamInputStreamReader 보조 스ㅡ림을 연결하는 코드는 다음과 같다.
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Example {
    InputStream is = new FileInputStream("...");
    InputStreamReader reader = new InputStreamReader(is);
}
  • 보조 스트림은 또 다른 보조 스트림과 연결되어 스트림 체인으로 구성할 수 있다.

Double Secondary Stream

  • 예를 들어 문자 변환 보조 스트림은 InputStreamReaderBufferedReader 보조 스트림을 연결하는 코드는 다음과 같다.
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Example {
    InputStream is = new FileInputStream("...");
    InputStreamReader reader = new InputStreamReader(is);
    BufferedInputStream br = new BufferedInputStream(reader);
}
보조 스트림기능
InputStreamReader바이트 스트림을 문자 스트림으로 변환
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
입출력 성능 향상
DataInputStream
DataOutputStream
기본 타입 데이터 입출력
PrintStream
PrintWriter
줄바꿈 처리 및 형식화된 문자열 출력
ObjectInputStream
ObjectOutputStream
객체 입출력

문자 변환 스트림

  • 바이트 스트림(InputStream, OutputStream)에서 입출력할 데이터가 문자라면 문자 스트림(ReaderWriter)로 변환해서 사용하는 것이 좋다.
  • 그 이유는 문자로 바로 입출력하는 편리함이 있고, 문자셋의 종류를 지정할 수 있기 때문이다.
InputStream을 Reader로 변환
  • InputStreamReader로 변환하려면 InputStreamReader 보조 스트림을 연결하면 된다.

Input Reader Stream

import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

public class Example {
    InputStream is = new FileInputStream("파일경로.파일확장명");
    Reader reader = new InputStreamReader(is);
}
  • FileReader의 원리

    FileInputStream에 InputStreamReader을 연결하지 않고 FileReader를 직접 생성할 수 있다.
    FileReader는 InputStreamReader의 자식 클래스이다.
    이것은 FileReader가 내부적으로 FileInputStream에 InputStreamReader 보조 스트림을 연결한 것이라고 볼 수 있다.

OutputStream을 Writer로 변환
  • OutputStreamWriter로 변환하려면 OutputStreamWriter 보조 스트림을 연결하면 된다.

Output Stream Writer

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

public class Example {
    OutputStream os = new FileOutputStream("파일경로/파일명.확장자명");
    Writer writer = new OutputStreamWriter(os);
}
  • FileWriter의 원리

    FileOutputStream에 OutputStreamWriter를 연결하지 않고 FileWriter를 직접 생성할 수 있다.
    FileWriter는 OutputStreamWriter의 자식 클래스이다.
    이것은 FileWriter가 내부적으로 FileOutputStream에 OutputStreamWriter 보조 스트림을 연결한 것이라고 볼 수 있다.

Continue with OutputStream을 Writer로 변환 Commit


Reference

Back to [Routine] 7 주차 시작!

Continue with [Routine] 9 주차 시작!

[Routine] 7 주차 시작!

[Routine] 7 주차 시작!

2023년 2월 27일 부터 3월 05일 까지의 나의 루틴.

#목차

2023-02-27

2023-02-27

  • 오늘도 어김없이 영한 님의 인강을 들으면서 출근하였다.
  • 스프링의 핵심원리 기초편이라 아는 부분이 많아서 따로 코드를 작성하지 않으려 한다.
  • 내가 모르는 부분이 있을때 코드로 작성하려고 한다.

컬렉션 자료구조(Set)

Set Collection

  • List 컬렉션은 저장 순서를 유지하지만, Set 컬렉션은 저장 순서가 유지되지 않는다.
  • 또한 객체를 중복해서 저장할 수 없고, 하나의 null만 저장할 수 있다.
  • Set 컬렉션은 수학의 집합에 비유될 수 있다. 집합은 순서와 상관없고 중복이 허용되지 않기 때문이다. Set Collection
기능메서드설명
객체
추가
boolean add(E e)주어진 객체를 성공적으로 저장하면 true를 리턴하고 중복 객체면 false를 리턴
객체
검색
boolean contains(Object o)주어진 객체가 저장되어 있는지 여부
isEmpty()컬렉션이 비어있는지 조사
Iterator<E> iterator()저장된 객체를 한 번씩 가져오는 반복자 리턴
int size()저장된 모든 객체를 삭제
객체
삭제
void clear()저장된 모든 객체를 삭제
boolean remove(Object o)주어진 객체를 삭제

HashSet

  • Set 컬렉션 중에서 가장 많이 사용되는 것이 HashSet이다.
  • HashSet은 동일한 객체는 중복 저장하지 않는다. 여기서 동일한 객체란 동등 객체를 말한다.
  • HashSet은 다른 객체라도 hashCode() 메서드의 리턴값이 같고, equals() 메서드가 true를 리턴하면 동일한 객체라고 판단하고 중복 저장하지 않는다. Set Collection
public class Set {
    Set<E> set = new HashSet<E>();  // E에 지정된 타입의 객체만 저장
    Set<E> set = new HashSet<>();   // E에 지정된 타입의 객체만 저장
    Set set = new HashSet();        // 모든 타입의 객체를 저장
}
  • Set 컬렉션은 인덱스로 객체를 검색해서 가져오는 메서드가 없다. 대신 객체를 한 개씩 반복해서 가져와야 하는데, 여기에는 두 가지 방법이 있다.
//file: "for 문을 이용한 방법.java"
public class SetUsingFor {
    public static void main(String[] args) {
        Set<E> set = new HashSet<E>();
        for (E e : set) {
            System.out.println("for Set : " + e);
        }
    }
}
  • Set 컬렉션의 iterator() 메서드로 반복자(iterator)를 얻어 객체를 하나씩 가져오는 것. 타입 파라미터 ESet 컬렉션에 저장되어 있는 객체의 타입이다.
//file: "set.iterator()를 사용하는 방법.java"
public class SetIterator {
    Set<E> set = new HashSet<E>();
    Iterator<E> iterator = set.iterator();
}
  • iteratorSet 컬렉션의 객체를 가져오거나 제거하기 위해 다음 메서드를 제공.
리턴 타입메서드 명설명
booleanhasNest()가져올 객체가 있으면 true를 리턴하고 없으면 false를 리턴한다.
Enext()컬렉션에서 하나의 객체를 가져온다
voidremove()next()로 가져온 객체를 Set 컬렉션에서 제거한다.
  • 사용방법
public class UsingHashNext {
    public static void main(String[] args) {
        while (iterator.hasNext()) {
            E e = iterator.next();
        }
    }
}

Continue with HashSet Commit

Map Collection

  • Map 컬렉션은 키key와 값value으로 구성된 엔트리Entry 개게를 저장한다. 여기서 키와 값은 모두 객체이다. 키는 중복 저장할 수 없지만 값은 중복 저장할 수 있다.
  • 기존에 저장된 키와 동일한 키로 값을 저장하면 기존의 값은 없어지고 새로운 값으로 대치된다. Map Collection
기능메서드설명
객체
추가
V put(K key, V value)주어진 키와 값을 추가, 저장이 되면 값을 리턴
객체
검색
boolean containsKey(Object key)주어진 키가 있는지 여부
boolean containsValue(Object key)주어진 값가 있는지 여부
Set<Map.Entry<K, V>> entrySet()키와 값의 쌍으로 구성된 모든 Map.Entry 객체를 Set에 담아서 리턴
V get(Object key)주어진 키의 값을 리턴
boolean isEmpty()컬렉션이 비어있는지 여부
Set<k> keySet()저장된 키의 총 수를 리턴
int size()저장된 키의 총 수를 리턴
Collection<V> values()저장된 모든 값 Collection에 담아서 리턴
객체
삭제
void clear()모든 Map.Entry(키와 값)를 삭제
V remove(Object key)주어진 키와 일치하는 Map.Entry 삭제, 삭제가 되면 값을 리턴

HashMap

  • HashMapkey로 사용할 객체가 hashCode() 메서드의 리턴값이 같고 equalse() 메서드가 true를 리턴할 경우, 동일 키로 보고 중복 저장을 허용하지 않는다. HashMap
public class HashMap {
    Map<String, Integer> map = new HashMap<String, Integer>();  // Key는 String 타입만, Value 값은 Integer만 가능
    Map<String, Integer> map = new HashMap<>();
}

Continue with HashMap Commit

Hashtable

  • HashtableHashMap과 동일한 내부 구조를 가지고 있다. 차이점은 Hashtable은 동기화된(synchronized) 메서드로 구성되어 있기 때문에 멀티 스레드가 동시에 Hashtable의 메서드들을 실행할 수 없다는 것이다.
  • 따라서 멀티 스레드 환경에서도 안전하게 객체를 추가, 삭제할 수 있다.

Hashtable

public class Hashtable {
    Map<String, Integer> map = new HashMap<String, Integer>();
    Map<String, Integer> map = new HashMap<>();
    Map map = new HashMap();    // <- 해당 경우는 거의 없다.
}

Continue with Hashtable Commit


2023-02-28

2023-02-28

  • 늦잠을 자버렸다…😅
  • 어김없이 영한 님의 인강과 함께 출근을 하였다.
  • 오늘 HashSet 다시 복습을 하는데 for 문과 iterator에서의 차이점을 새로 알게 되었다.
  • 간략하게 말하자면 for 문은 몇 번 반목할지 이미 알고 있는 상태. 즉, 반복문 실행 중 반복할 횟수의 대상을 제거하면 Exception이 발생하게 된다. 이때 for 문이 아닌 iterator을 사용해야 한다.

// file: "IteratorRemoveErrorExample.java"
public class IteratorRemoveError {
    public static void main(String[] args) {
        Set<String> whileSet = new HashSet<String>();
        whileSet.add("Java");
        whileSet.add("Spring");
        whileSet.add("JDBC");
        whileSet.add("JPA");

        // 에러 예제 for 문
        for (String element : whileSet) {
            System.out.println("객체를 하나씩 가져와서 처리 element : " + element);
            // 에러 예제
            if (element.equals("Java")) {
                whileSet.remove(element);
                // exception 발생
                // Exception in thread "main" java.util.ConcurrentModificationException
                // at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1597)
                // at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1620)
                // at ch15.collection_framwork.HashSetExample.main(HashSetExample.java:73)
            }
        }
    }
}
  • 위 문제 발생을 아래와 같이 해결 할 수 있다.
public class IteratorRemoveTroubleshooting {
    public static void main(String[] args) {
        // file: "IteratorRemoveTroubleshootingExample.java"
        Set<String> whileSet = new HashSet<String>();
        whileSet.add("Java");
        whileSet.add("Spring");
        whileSet.add("JDBC");
        whileSet.add("JPA");

        // 문제 해결 예제
        Iterator<String> iterator = whileSet.iterator();
        while (iterator.hasNext()) {
            String element = iterator.next();
            System.out.println("while() element : " + element);
            if (element.equals("Spring")) {
                iterator.remove();
            }
        }
    }
}

컬렉션 자료구조(Set)

Map Collection

Properties
  • PropertiesHashtable의 자식 클래스이기 때문에 Hashtable의 특징을 그대로 가지고 있다.
  • Properties키와 값을 String 타입으로 제한한 컬렉션이다. Properties는 주로 확장자가 .properties인 프로퍼티 파일을 읽을 때 사용한다.
  • 프로퍼티 파일은 다음과 같이 키와 값이 = 기호로 연결되어 있는 텍스트 파일이다.
  • 일반 텍스트 파일과 다르게 ISO 8859-1 문자셋으로 저장되며, 한글이리 경우에는 \u+유니코드로 표현되어 저장된다.
# file: "database.properties"
driver=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:orcl
username=java
paswsord=java
admin=\uD64D\uAE38\uB3D9
public class Properties {
    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.load(XXX.class.getResourceAsStream("database.properties"));
    }
}

Continue with Properties Commit

검색 기능을 강화시킨 컬렉션을

  • 컬렉션 프레임워크는 검색 기능을 강화시킨 TreeSetTreeMap을 제공한다. 이름에서 알 수 있듯이 TreeSetSet 컬렉션이고, TreeMapMap 컬렉션이다.
TreeSet
  • TreeSet은 이진 트리binary tree를 기반으로 한 Set 컬렉션이다. 이진 트리는 여러 개의 노드node가 트리 형태로 연결된 구로조, 루트 노드root node라고 불리는 하나의 노드에서 시작해 각 노드에 최대 2개의 노드를 연결할 수 있는 구조를 가지고 있다. RootNode
  • TreeSet에 객체를 저장하면 다음과 같이 자동으로 정렬된다. 부모 노드의 객체와 비교해서 낮은 것은 왼쪽 자식 노드에, 높은 것은 오른쪽 자식 노드에 저장한다. Node
public class TreeSet {
    TreeSet<E> treeSet = new TreeSet<E>();
    TreeSet<E> treeSet = new TreeSet<>();
}
<div style="width:150px">리턴 타입</div><div style="width:200px">메서드</div>설명
Efirst()제일 낮은 객체를 리턴
Elast()제일 높은 객체를 리턴
Elower(E e)주어진 객체보다 바로 아래 객체를 리턴
Ehigher(E e)주어진 객체보다 바로 위 객체를 리턴
Efloor(E e)주어진 객체와 동등한 객체가 있으면 리턴, 만약 없다면 주어진 객체의 바로 아래의 객체를 리턴
Eceiling(E e)주어진 객체와 동등한 객체가 있으면 리턴, 만약 없다면 주어진 객체의 바로 위의 객체를 리턴
EpollFirst()제일 낮은 객체를 꺼내오고 컬렉션에서 제거함
EpollLast()제일 높은 객체를 꺼내오고 컬렉션에서 제거함
Iterator<E>descendingIterator()내림차순으로 정렬된 Iterator를 리턴
NavigableSet<E>descendingSet()내림차순으로 정렬된 NavigableSet을 리턴
NavigableSet<E>headSet(
   E toElement,
   boolean inclusive
}
주어진 객체보다 낮은 객체들을 NavigableSet으로 리턴, 주어진 객체 포함 여부는 두 번째 매개값에 따라 달라짐
NavigableSet<E>tailSet(
   E toElement,
   boolean inclusive
}
주어진 객체보다 높은 객체들을 NavigableSet으로 리턴, 주어진 객체 포함 여부는 두 번째 매개값에 따라 달라짐
NavigableSet<E>tailSet(
   E toElement,
   boolean inclusive
   E toElement,
   boolean toInclusive
}
시작과 끝으로 주어진 객체 사이의 객체들을 NavigableSet으로 리턴, 시작과 끝 객체의 포함 여부는 두 번째,네 번째 매개값에 따라 달라짐

Continue with TreeSet Commit

TreeMap
  • TreeMap은 이진 트리를 기반으로 한 Map 컬렉션이다. TreeSet과의 차이점은 키와 값이 저장된 Entry를 저장한다는 점이다.
  • TreeMap에 엔트리를 저장하면 키를 기준으로 자동 정렬되는데, 부모 키 값과 비교해서 낮은 것은 왼쪽, 높은 것은 오른쪽 자식 노드에 Entry 객체를 저장한다. node
public class TreeMap {
    TreeMap<K, V> treeMap = new TreeMap<K, V>();
    TreeMap<K, V> treeMap = new TreeMap<>();
}
<div style="width:170px">리턴 타입</div><div style="width:200px">메서드</div>설명
Map.EntryfirstEntry()제일 낮은 Map.Entry를 리턴
Map.EntrylastEntry()제일 높은 Map.Entry를 리턴
Map.EntrylowerEntry(K key)주어진 키보다 바로 아래 Map.Entry를 리턴
Map.EntryhigherEntry(K key)주어진 키보다 바로 위 Map.Entry를 리턴
Map.EntryfloorEntry(K key)주어진 키와 동등한 키가 있으면 해당 Map.Entry를 리턴, 없다면 주어진 키 바로 아래의 Map.Entry를 리턴
Map.EntryceilingEntry(K key)주어진 키와 동등한 객체가 있으면 해당 Map.Entry를 리턴, 없다면 주어진 키의 바로 위의 Map.Entry를 리턴
Map.EntrypollFirst()제일 낮은 Map.Entry를 꺼내오고 컬렉션에서 제거함
Map.EntrypollLast()제일 높은 Map.Entry를 꺼내오고 컬렉션에서 제거함
NavigableSet<E>   descendingKeySet()내림차순으로 정렬된 키의 NavigableSet을 리턴
NavigableMap<K, V>descendingMap()내림차순으로 정렬된 Map.EntryNavigableMap을 리턴
NavigableMap<K, V>headMap(
   K toKey,
   boolean inclusive
)
주어진 키보다 낮은 Map.Entry들을 NavigableMap으로 리턴, 주어진 키의 Map.Entry 포함 여부는 두 번째 매개값에 따라 달라짐
NavigableMap<K, V>tailMap(
   K toKey,
   boolean inclusive
)
주어진 객체보다 높은 Map.Entry들을 NavigableSet으로 리턴, 주어진 객체 포함 여부는 두 번째 매개값에 따라 달라짐
NavigableMap<K, V>subMap(
   K toKey,
   boolean inclusive,
   K toKey,
   boolean toInclusive
)
시작과 끝으로 주어진 키 사이의 Map.Entry들을 NavigableMap컬렉션으로 반환, 시작과 끝 키의 Map.Entry 포함 여부는 두 번째,네 번째 매개값에 따라 달라짐

Continue with TreeMap Commit


2023-03-01

  • 9시 30분까지 늦잠을 잤다…😁

컬렉션 자료구조(Set)

검색 기능을 강화시킨 컬렉션

Comparable 과 Comparator
  • TreeSet에 저장되는 객체와 TreeMap에 저장되는 키 객체는 저장과 동시에 오름차순으로 정렬되는데, 어떤 객체든 정렬될 수 있는 것은 아니고 객체가 Comparable 인터페이스를 구현하고 있어야 가능하다.
  • Integer, Double, String 타입은 모두 Comparable을 구현하고 있기 때문에 상관 없지만, 사용자 저으이 객체를 저장할 때에는 반드시 Comparable을 구현하고 있어야 한다.
리턴타입메서드설명
intcompareTo(T o)주어진 객체와 같으면 0을 리턴
주어진 객체보다 적으면 음수를 리턴
주어진 객체보다 크면 양수를 리턴

Continue with Comparable Commit

  • 비교 기능이 있는 Comparable 구현 객체를 TreeSet에 저장하거나 TreeMap의 키로 저장하는 것이 원칙이지만, 비교 기능이 없는 Comparable 비구현 객체를 저장하고 싶다면 방법은 없진 않다.
  • TreeSetTreeMap을 생성할 때 비교자Comparator를 다음과 같이 제공하면 된다.
public class ComparatorImpl {
    // new ComparatorImpl() ==> 비교자
    TreeSet<E> treeSet = new TreeSet<E>(new ComparatorImpl());
    TreeMap<K, V> treeMap = new TreeMap<K, V>(new ComparatorImpl());
}
  • 비교자는 Comparator 인터페이스를 구현한 객체를 말하는데, Comparator 인터페이스에는 compare() 메서드가 정의도어 있다.
리턴 타입메서드설명
intcompareTo(T o1, T 02)o1과 o2가 동등하다면 0을 리턴
o1이 o2보다 앞에 오게 하려면 음수를 리턴
o1이 o2보다 뒤에 오게 하려면 양수를 리턴

Continue with Comparator Commit

LIFO 와 FIFO 컬렉션

  • 후입선출(LIFO,Last In Out)나중에 넣은 객체가 먼저 빠져나가고, 선입선출(FIFO,First IN First Out)먼저 넣은 객체가 먼저 빠져나가는 구조를 말한다.
  • 컬렉션 프레임워크는 LIFO 자료구조를 제공하는 스택Stack 클래스와 FIFO 자료구조를 제공하는 Queue 인터페이스를 제공하고 있다. node

  • 스택을 응용한 대표적인 예가 JVM 스택 메모리이다.
  • 스택 메모리에 저장된 변수는 나중에 저장된 것부터 제거된다.
  • 큐를 응용한 대표적인 예가 스레드 풀(ExecutorService)의 작업 큐이다.
Stack
  • Stack 클래스는 LIFO 자료구조를 구현한 클래스이다.
import java.util.Stack;

public class StackExample {
    Stack<E> stack = new Stack<E>();
    Stack<E> stack = new Stack<>();
}
리턴 타입메서드설명
Epush(E item)주어진 객체를 스택에 넣는다.
Epop()스택의 맨 위 객체를 빼낸다.

Continue with Stack Commit

Queue
  • Queue 인터페이스는 FIFO 자료구조에서 사용되는 메서드를 정의하고 있다.
리턴 타입메서드설명
booleanoffer(E e)주어진 객체를 큐에 넣는다.
Epoll()큐에서 객체를 빼낸다.
public class Queue {
    Queue<E> queue = new LinkedList<E>();
    Queue<E> queue = new LinkedList<>();
}

Continue with Queue Commit

동기화된 컬렉션

  • 컬렉션 프레임워크의 대부분의 클래스들은 싱글 스레드 환경에서 사용할 수 있도록 설계되었다.
  • 그렇기 때문에 여러 스레드가 동시에 컬렉션에 접근한다면 의도하지 않게 요소가 변경될 수 있는 불안전한 상태가 된다.
  • VectorHashtable은 동기화된(synchronized) 메서드로 구성되어 있기 때문에 멀티 스레드 환경에서 안전하게 요소를 처리할 수 있지만, ArrayList, HashSet, HashMap은 동기화된 메서드로 구성되어 있지 않아 멀티 스레드 환경에서 안전하지 않다.
  • 이 경우 멀티 스레드 환경에서 사용하고 싶을 때가 있을 것이다. 이런 경우를 대비해서 컬렉션 프레임워크는 비동기화된 메서드를 동기화된 메서드로 래핑하는 CollectionsynchronizedXXX() 메서드를 제공한다.
리턴 타입메서드(매개변수)설명
List<T>synchronizedList(List<T> list)List를 통기화된 List로 리턴
Map<K, V>synchronizedMap(Map<K, V> m)Map를 통기화된 Map로 리턴
Set<T>synchronizedSet(Set<T> s)Set를 통기화된 Set로 리턴
  • ArrayListCollections.synchronizedList() 메서드를 사용해서 동기화된 List로 변환된다. synchronized_collection_1
  • HashSetCollections.synchronizedSet() 메서드를 사용해서 동기화된 Set로 변환된다. synchronized_collection_2
  • HashSetCollections.synchronizedMap() 메서드를 사용해서 동기화된 Map로 변환된다. synchronized_collection_3
public class SynchronizedMap {
    Map<Integer, String> map = Collections.synchronizedMap(new HashMap<>());    // 출력 : 일정한 값
    Map<Integer, String> map = new HashMap<>();    // 출력 : 일정하지 않은 값
}
  • HashMap은 두 스레드가 동시에 put() 메서드를 호출할 수 있기 때문에 경합이 발생하고 결국 하나만 저장되기 때문이다.
  • 하지만 동기화된 Map은 한 번에 하나의 스레드만 put() 메서드를 호출할 수 있기 때문에 경합이 발생하지 않는다.

Continue with SynchronizedMap Commit

수정할 수 없는 컬렉션

  • 수정할 수 없는(unmodifiable) 컬렉션이란 요소를 추가, 삭제할 수 없는 컬렉션을 말한다.
  • 첫 번째 방법으로는 List, Set, Map 인터페이스의 정적 메서드인 of()로 생성할 수 있다.
    public class Of {
      List<E> immutableList = List.of(E... elements);
      Set<E> immutableSet = Set.of(E... elements);
      Map<K, V> immutableMap = Map.of(K k1, V v1, K k2, V v2, ...);
    }
    
  • 두 번째 방법은 List, Set, Map 인터페이스의 정적 메서드인 copyOf()을 이용해 기존 컬렉션을 복사하여 수정할 수 없는 컬렉현을 만든는 것이다.
    public class CopyOf {
      List<E> immutableList = List.copyOf(Collection<E> coll);
      Set<E> immutableSet = Set.copyOf(Collection<E> coll);
      Map<K, V> immutableMap = Map.copyOf(Map<K, V> map);
    }
    
  • 세 번째 방법은 배열로부터 수정할 수 없는 List 컬렉션을 만들 수 있다.
    public class AsList {
      String[] arr = {"A", "B", "C"};
      List<String> immutableList = Arrays.asList(arr);
    }
    

Continue with Unmodifiable Commit


2023-03-02 스터디

2023-03-02

  • 오늘도 어김없이 영한 님의 인강을 듣고 출근했다.
  • 지금 영한 님의 새로운 인강이 출시되어 월급 받으면 바로 결제할 예정이다.
  • 지금 얼리버드 할인 적용이 되어 30% 저렴하게 구매할 수 있다. 오늘도 열공 열일하자…🤩

람다식이란?

  • 함수형 프로그래밍function programming이란 함수를 정의하고 이 함수를 데이터 처리부로 보내 데이터를 처리하는 기법을 말한다.
    • 함수 vs 메서드
      • 함수 : 객체와 상관없이 실행가능한 코드 블럭, 주로 javascriptfunction() { ... }을 말한다.
      • 메서드 : 반드시 객체 안에 존재해야 한다. 즉, 객체 기능을 정의한다. 메서드는 class, object로 감싸져있어야 한다.

Lambda

  • 데이터 처리부는 제공된 함수의 입력값으로 데이터를 넣고 함수에 정의된 처리 내용을 실행한다.
  • 동일한 데이터라도 함수A를 제공해서 처리하는 결과와 함수B를 제공해서 처리하는 결과는 다를 수 있다. 이것이 함수형 프로그래밍의 특징으로, 데이터 처리의 다형성데이터 처리의 다형성이라고도 볼 수 있다.
  • 람다식Lambda Expressions은 데이터 처리부에 제공되는 함수 역할을 하는 매개변수를 가진 중괄호 블록이다.
    람다식: (매개변수, ...) -> { 처리내용 }
    
  • 자바는 람다식을 익명 구현 객체로 변환한다.
    public class AnonymousTest {
      public void action(Calculable calculable) {
          int x = 10;
          int y = 4;
          Calculable.calculable(x, y);    // 데이터를 제공하고 추상 메서드를 호출
      }
    }
    

Lambda

  • 람다식은 두 개 이상의 추상 메서드를 가진 인터페이스는 람다식으로 표현할 수 없다.
  • 인터페이스가 단 하나의 추상 메서드를 가질 때, 이를 함수형 인터페이스functional interface라고 한다.
인터페이스람다식
public interface Runnable {
   void run();
}
() -> { ... }
@FunctionalInterface
public interface Calculable {
   void calculate(int x, int y);
}
(x, y) -> { ... }
  • 인터페이스가 함수형 인터페이스임을 보장하기 위해서는 @FunctionalInterface 어노테이션을 붙이면 된다.
  • @FunctionalInterface를 붙이는 것은 선택사항이지만, 컴파일 과정에서 추상 메서드가 하나인지 검사하기 때문에 정확한 함수형 인터페이스를 작성할 수 있게 도와준다.

Continue with Basic Lambda Expressions Commit


스터디 발표

자바스크립트 내장객체

Number 객체

  • toString() : 숫자형 데이터를 문자형 데이터로 반환
  • toExponential() : 숫자를 지수형으로 반환 (지수 = 과학이나 공학에서 아주 큰 숫자를 표기하는 기법 )
  • toFixed() : 소수점 몇 번째 자리까지 보여줄지 결정하는 함수. 반올림 값 반환
  • toPrecision() : 정수와 소수를 포함해서 몇 번째 자리까지 보여줄지 결정하는 함수. 반올림 값 반환
  • parseInt() : 정수로 반환. 문자열의 시작이 숫자형 이어야지 반환.
  • parseFloat() : 부동소수점으로 반환.
    Array 객체
  • toString() : 배열 안의 모든 문자를 쉼표(,)를 이용해 결합해서 하나의 문자열로 반환
  • join() : 배열 안의 모든 문자를 파라미터로 지정한 문자를 이용해서 모두 결합해서 하나의 문자열로 반환
  • pop() : 배열에서 마지막 데이터를 제거하고, 마지막 데이터 반환
  • push() :
  • shift() : 배열에서 첫 번째 요소를 제거하고, 첫 번째 요소를 반환
  • unshift() : 배열의 맨 앞에 요소를 추가하고, 배열의 길이를 반환. select 박스의 첫 번째 문장 -> 선택하세요
  • splice() : 새로운 요소를 특정 위치에 추가. 기존 요소 삭제 가능
  • concat() : 2개 이상의 배열을 하나의 배열로 반환

왕돼지티라노의 기록 - JPA 영속성 관리2

^.^ - HTTP


  • 오늘은 회사에서 vue로 마이너그래이션 작업하던 중 검색 조건에서의 컴포넌트화 진행하던 중 초기화 버튼을 누르면 해당 컴포넌트가 초기화되는 작업을 진행하는 데 애를 먹었다.
  • 결국 완벽하게 완성되진 않았지만 기능적으론 동작하게 되었다. 개발자 도구를 보니 warning 문구가 나오는 것을 확인 하구 내일 출근해서 처리할 예정이다. 그것 때문에 30분 정도 늦게 마치고 퇴근하였다.
  • 퇴근 후 다음 주 발표 있을 자료를 준비를…🤩

2023-03-03

2023-03-03

  • 어제 늦게 자서 오늘 좀 늦잠을 잤다…😋
  • 오늘도 역시 영한 님의 인강을 듣고 출근하였고 이것이 자바다를 얼른 다 읽고 영한 님의 스프링 강의를 제대로 공부해야겠다는 생각이 들었다.
  • 오늘 오전 공부는 워니님의 인강을 들었다.
  • 새롭게 알게 된 내용이 내 이력서를 업데이트하면서 나의 부족한 점을 찾아내고 나의 현재 상태를 잘 파악할 수 있다는 점이다.
  • 그럼으로써 나의 이력서는 다듬어지고 나의 부족한 점을 찾아 메울 수 있다는 것인데, 이런 생각을 왜 늦게 했을까? 하는 아쉬움이 남았다.
  • 그래서 오늘부터 일정 시간을 나의 이력서 작성하는 것에 시간을 사용하려 한다.

2023-03-04

  • 오늘은 9시에 일어나 준비를 하고 10시 10분쯤 머리를 하러 갔다. 애즈펌을 했는데 나름 만족한다.😙
  • 그리고 여자친구를 만나서 광화문에 가서 이탈리아 식당에서 맛있는 밥을 먹고 내가 제일 좋아하는 광화문 교보문고에 갔다.
  • 새 학기라 아이들 손을 잡고 오신 부모님들이 많았다. 그리고 핫트랙스에서 필기도구를 20% 할인하고 있어서 사람들이 더 많았다.
  • 한 2시간 정도 있었는데 I 라인에 기술서가 있는 곳에서 시간을 다 보냈다.
  • 너무 보고 싶은 책들이 많아 어떤 책을 사야 할지 고민을 하던 중 Clean Code로 유명한 로버트 C. 마틴 저자의 클린 소프트웨어을 선택했다.
  • 선택한 이유는 애자일에 대해 생소한 부분도 있었고 테스트 주도 개발, SOLID, 사례를 통한 패턴이어서 너무 끌렸다.
  • 그리고 동욱(향로) 님의 스프링 부트와 AWS로 혼자 구현하는 웹 서비스구글 엔지니어는 이렇게 일한다를 인터넷으로 주문하였다.
  • 인터넷이 좀 더 저렴하기도 하고 책 상태가 좋지 않아 인터넷으로 주문하였다.
  • 역시 향로님의 책은 IntelliJ로 시작한다는 점과 AWS를 활용과 더불어 테스트에 대해 작성해 주셔서 너무 보고 싶던 책이었다.
  • 문화, 도구, 프로세스, 코드 리뷰, 대규모 변경 등을 간접적으로 느껴보고 싶어서 구매하였다.

2023-03-05

  • 10시에 기상… 늦잠을 잤다…🤫

람다식이란?

매개변수가 없는 람다식

실행문이 두 개 이상실행문이 하나일 경우
() -> {
   실행문;
   실행문;
}
() -> 실행문

Continue with No-Parameters Lambda Expressions Commit

  • 다음은 ch09.nested_declaration_and_anonymous_objects 에서 구현한 익명 구현 객체 예제를 람다식으로 대체한 예제로 바꾸어 보았다.

Continue with No-Parameters Anonymous-Objects Lambda Expressions Commit

매개변수가 있는 람다식

  • 함수형 인터페이스의 추상 메서등에 매개변수가 있을 경우 람다식은 다음과 같이 작성할 수 있다.
  • 매개변수를 선언할 때 타입은 생략할 수 있고, 구체적인 타입 대신에 var를 사용할 수 도 있다. 하지만 타입을 생략하고 작성하는 것이 일반적이다.
실행문이 두 개 이상인 경우  
(타입 매개변수, ...) -> {
   실행문;
   실행문;
}
(var 매개변수, ...) -> {
   실행문;
   실행문;
}
(매개변수, ...) -> {
   실행문;
   실행문;
}
실행문이 한 개인 경우  
(타입 매개변수, ...) -> 실행문(var 매개변수, ...) -> 실행문(매개변수, ...) -> 실행문
매개변수가 하나일 경우에는 괄호를 생략할 수 있다 
타입 매개변수 -> {
   실행문;
   실행문;
}
매개변수 -> 실행문

Continue with Parameters Lambda Expressions Commit

리턴값이 있는 람다식

리턴값이 있는 람다식 
(매개변수, ...) -> {
   실행문;
   return 값;
}
(매개변수, ...) -> 값

Continue with Return Lambda Expressions Commit

메서드 참조

  • 메서드 참조는 메서드를 참조해서 매개변수의 정보 및 리턴 타입을 알아내 람다식에서 불필요한 매개변수를 제거하는 것을 목적으로 한다.
(left, right) -> Math.max(left, right);
// 위 코드를 아래 코드로 함축하여 사용할 수 있다.
Math :: max;
정적 메서드와 인스턴스 메서드 참조
  • 정적static 메서드를 참조할 경우에는 클래스 이름 뒤에 :: 기호를 붙이고 정적 메서드 이름을 기술한다.
  • 인스턴스 메서드일 경유에는 먼저 객체를 생성한 다음 참조 변수 뒤에 :: 기호를 붙이고 인스턴스 메서드 이름을 기술한다.
// 정적 메서드
클래스 :: 메서드

// 인스턴스 메서드
참조변수 :: 메서드

Continue with Method Reference Lambda Expressions Commit

매개변수의 메서드 참조
  • 람다식에서 제공되는 a 매개변수의 메서드를 호출해서 b 매개변수를 매개값으로 사용하는 경우가 있다.
(a, b) -> { a.instanceMethod(b); }
  • a의 클래스 이름 뒤에 :: 기호를 붙이고 메서드 이름을 기술한다.
  • 정적 메서드 참조와 동일하지만, a의 인스턴스 메서드가 사용된다는 점에서 다르다.
클래스 :: instanceMethod

Continue with Method Reference of Parameters Lambda Expressions Commit

생성자 참조

  • 생성자를 참조한다는 것은 객체를 생성하는 것을 의미한다.
  • 람다식이 단순히 객체를 생성하고 리턴하도록 구성된다면 람다식을 생성자 ㅏㅁ조로 대치할 수 있다.
(a, b) -> { return new 클래스(a, b); }
  • 이것을 생성자 참조로 표현한다면 아래와 같이 클래스 이름 뒤에 :: 기호를 붙이고 new 연산자를 기술하면 된다.
클래스 :: new
  • 생성자가 오버로딩되어 여러 개가 있을 경우, 컴파일러는 함수형 인터페이스의 추상 메서드와 동일한 매개변수 ㅏ입과 개수를 가지고 있는 생성자를 찾아 실행한다.
  • 만약 해당 생성자가 존재하지 않으면 컴파일 오류가 발생한다.

Continue with Constructor Reference Lambda Expressions Commit

스트림 요소 처리

스트림이란?

  • Java8 부터는 컬렉션 및 배열의 요소를 반복 처리하기 위해 스트림stream을 사용할 수 있다.
public class Stream {
    public static void main(String[] args) {
        Stream<String> stream = list.stream();
        stream.forEach( item -> System.out.println(item) );
    }
}
  • StreamIterator와 비슷한 반복자이니지만, 차이점을 가지고 있다.
    1. 내부 반복자이므로 처리 속도가 빠르고 병렬 처리에 효율적이다.
    2. 람다식으로 다양한 요소 처리를 정의할 수 있다.
    3. 중간 처리최종 처리 를 수행하도록 파이프 라인을 형성할 수 있다.

Continue with Basic Stream Commit

내부 반복자

  • for문과 iterator는 컬렉션의 요소를 컬렉션 바깥쪽으로 반복해서 가져와 처리하는데, 이것을 외부 반복자라고 한다.
  • Stream은 요소 처리 방법을 컬렉션 내부로 주입시켜서 요소를 반복 처리하는데, 이것을 내부 반복자라고 한다. Inner Outer Iterator
  • 외부 반복자일 경우는 컬렉션의 요소를 외부로 가져오는 코드와 처리하는 코드를 모두 개발자 코드가 가지고 있어야 한다.
  • 반면, 내부 반복자일 경우는 개발자 코드에서 제공한 데이터 처리 코드(람다식)를 가지고 컬렉션 내부에서 요소를 반복 처리한다.
  • 내부 반복자는 멀티 코어 CPU를 최대한 활용하기 위해 요소들을 분배시켜 병렬작업을 할 수 있다.
  • 하나씩 처리하는 순차적 외부 반복자보다는 효율적으로 요소를 반복시킬 수 있는 장점이 있다.
  • 반면, 처리 내용이 적은 경우는 각 스레드들을 만들어야 하기 때문에 오히려 속도가 저하 될 수 있다는 단점이 있다. Inner Iterator

Continue with Parallel Stream Commit

중간 처리와 최종 처리

  • Stream은 하나 이상 연결되 수 있다. 컬렉션의 오리지널 스트림 뒤에 필터링 중간 스트림이 연결될 수 있고, 그 뒤에 매핑 중간 스트림이 연결될 수 있다. 이와 같이 스트림이 연결되어 있는 것을 스트림 파이프라인pipelines이라고 한다. Stream_Pipelines1
  • 오리지널 스트림과 집계 처리 사이의 중간 스트림들은 최종 처리를 위해 요소를 걸러내거나(필터링), 변환시키너나(매핑), 정렬하는 작업을 수행한다.
  • 최종 처리는 중간 처리에서 정제된 요소들을 반복하거나, 집계(카운팅, 총합, 평균) 작업을 수행한다. Stream_Pipelines2
public class StreamSuduent {
    // Student 스트림
    Stream<String> studentStream = list.stream();
    // score 스트림
    // Student 객체를 getScore() 메서드의 리턴값으로 매핑
    IntStream scoreStream = studentStream.mapToInt( student -> student.getScore() );
    // 평균 계산
    double avg = scoreStream.average().getAsDouble();
}
  • mapToInt() 메서드는 객체를 int 값으로 매핑해서 IntStream으로 변환시킨다.
  • 어떤 객체를 어떤 int 값으로 매핑할 것인지는 람다식으로 제공해야 한다.
  • student -> student.getScore()Student 객체를 getScore()의 리턴값으로 매핑한다.
  • InputStream은 최종 처리를 위해 다양한 메서드를 제공하는데, average() 메서드는 요소들의 평균 값을 계산한다.
public class StramMapToInt {
    double avg = list.stream()
            // mapToInt() 메서드는 int 값으로 매핑해서 IntStream으로 변환
            .mapToInt(student -> student.getScore())    // student -> student.getScore()는 Student 객체를 getScore()의 리턴값으로 매핑
            .average()  // 요소들의 평균 값을 계산
            .getAsDouble();
}

Continue with Stream Pipelines Commit


  • 오늘 하루는 일어나서 먹고 공부하고 먹고 공부하고 낮잠 자고 먹고 공부하고 한거 같다…😅
  • 곰 같은 하루를 보낸듯하다.

Reference

Back to [Routine] 6 주차 시작!

Continue with [Routine] 8 주차 시작!

[Network] OSI 7 Layer - Physical Layer

[Network] OSI 7 Layer - Physical Layer

“해당 포스팅은 우아한Tech[10분 테코톡] 🔮 히히의 OSI 7 Layer을 참고하여 포스팅하였습니다. 영상을 제작해주신 우아한Tech히히님에게 감사드립니다.”

#목차

Physical Layer

Physical Layer

두 대의 컴퓨터가 통신하려면?

모든 파일과 프로그램은 0과 1의 나열

Two Computer Communications

두 대의 컴퓨터를 전선 하나로 연결한다고 가정

  • 모든 파일과 프로그램은 0과 1의 나열이다.
  • 1을 보낼 때는 +5V의 전기를, 0을 보낼 때는 -5V의 전기를 전선으로 보낸다고 가정해 보자.
  • 이렇게 하면 01의 전송이 가능할 것이다.
  • 하지만, 위 방법은 문제가 있는데, 실제론 잘 작동하지 않는다.

실제론 잘 작동하지 않는 문제 발생

Sin Graph

전자기파를 표현하는 Sin 함수 그래프

  • 주파수란? 1초당 진동한 진동 횟수. 단위 : Hz(헤르츠)
  • 1초당 진동한 진동 횟수를 Hz(헤르츠)라고 하고, 위 예시는 1초에 4번의 사이클이기 때문에 4Hz(헤르츠)가 된다.
  • 위 그래프는 파동이 진행되는 내내 주파수가 4Hz(헤르츠)이다.

만약, 일정하지 않은 주파수이면?

Irregular Sin Graph

이런 전자기파는 주파수 값이 숫자 하나로 고정되지 않고, 파동이 진행되는 동안 주파수 값이 계속 변하게 된다.

  • 하지만, 위 그림처럼 일정하지 않은 주파수이면 어떻게 되는 것일까?
  • 위 전자기파의 주파수 최솟값이 1Hz, 최댓값이 10Hz라고 생각해 보자.
  • 그런데, 모든 전선에는 저항이 있어 전선에 맞는 허용 범위의 전류와 전압이 있다.
  • 즉, 전선은 모든 전류, 그리고 모든 주파수를 다 통과시키지 못하고 허용 범위가 생긴다.

모든 전선에는 저항이 있어 전선에 맞는 허용 범위의 전류와 전압이 존재

Electric Wire

KS C IEC - IEC(국제 전기 표준화 기구)를 KS(한국 산업 표준)에 맞게 표준화
2CX 2.5SQ MM - 2core(2가닥의 전선)와 각 전선의 굵기는 2.5SQ (MM) 2.5mm
300(상전압)/500(선간전압)V - 허용 범위의 전압(Volt), 국내 가정용 220V 표준
KS C IEC 53 - 케이블의 종류(해당 케이블은 VCTF)

  • 우리나라의 허용범위 주파수는 60Hz이다.
  • 이유는 우리나라 주파수는 왜 60Hz일까? 자료를 참고해 주시길 바란다.
    • 간단하게 설명하자면, 우리나라는 그 당시 미국의 영향을 많이 받아 미국 방식을 채택하게 된 것.

잘못된 데이터 수신

Problem

Hz의 허용 범위가 다른 전선의 사용한 경우 잘못된 데이터를 수신할 수 있게 되는 문제점 발생

  • 보내는 쪽에서는 1~10Hz의 데이터 안녕을 보낸다.
  • 하지만, 전선의 주파수 허용 범위가 5~8Hz여서 1~4Hz, 9~10Hz의 데이터가 손상이 된다.
  • 그래서 받은 데이터는 전혀 다른 데이터를 받게 되는 문제가 발생한다.
  • 그런데, 앞에서 두 대의 컴퓨터가 통신하려면 01을 주고받을 수 있으면 된다고 했는데, 그 방법은 두 대의 컴퓨터에 다음과 같은 전자기파를 주고받을 수 있으면 된다.

수직/수평선이 있는 전자기파

Vertical Horizontal_Wave

그런데, 수직선과 수평선이 있는 전자기파는 항상 0~무한대 Hz의 주파수 범위를 갖는다?

수직선과 수평선이 있는 전자기파는 편파(polarized) 전자기파이며, 편파 전자기파는 진폭이 한 방향으로 고정되어 있고, 이러한 편파 전자기파는 하나의 평면에서 전파가 진행된다.
따라서, 수직선과 수평선이 있는 전자기파의 주파수 범위는 항상 0 ~ 무한대(Hz)를 갖는다. 왜냐하면 편파 전자기파는 진폭이 한 방향으로 고정되어 있으며, 주파수는 전파의 진동수를 나타내기 때문이다.

따라서, 수직선과 수평선이 있는 전자기파는 특정한 주파수 범위에서만 발생하는 것이 아니라, 전체 주파수 범위에서 발생할 수 있다.

무한 vs 유한 전자기파

Vertical Horizontal_Wave

  • 위 내용을 나만의 해석을 통해 조금 더 쉽게 이해하자면…
  • 왼쪽 그래프에서는 0초에서 0.1초의 전압은 0V이기 때문에 전자기파가 생겨나지 않는다. 즉, 0Hz의 주파수를 갖는다.
  • 0.1초에서부터 +5V 이상의 수직적 전압이 발생하여 전자기파가 생겨났다.
  • 시간의 흐름에 따라 서서히 증가 또는 감소하는 것이 아니라 해당 시간에 수직으로 생겨난 전압이기 때문에 0.1초에는 측정 불가한 무한대의 Hz를 갖는다.
  • 오른쪽 그래프에서는 시간에 따라 서서히 전압이 증가 또는 감소하는 것을 볼 수 있다.
  • 따라서, 왼쪽 그래프는 시간이 변하지 않고 해당 시간에 수직적이고 무한한 전압이 생성되었기 때문에 측정 불가한 무한대의 Hz를 갖는 전자기파가 생성된다.
  • 오른쪽 그래프는 시간에 따라 변화하는 전압이 발생하므로 측정 가능한 유한대의 Hz를 갖는 전자기파가 생성된다.

  • 결론은, 이러한 무한한 Hz의 전기신호를 통과시킬 수 있는 전선은 없다.
  • 그렇다면 01의 신호를 어떻게 전송해야 할까?

디지털 신호를 아날로그 신호로

Digital to Analog

디지털 신호를 아날로그 신호로 바꿔서 전송해야 한다.

아날로그 신호의 특징

  • 아날로그 신호는 끊김 없이 연속된 신호로 이루어져 있다.
  • 신호의 세기를 아주 정밀하게 표현이 가능하다.
  • 거리에 따라 신호의 세기가 약해지면서 결국 소멸되는 특징을 가지고 있다.
  • 전자기파의 스펙트럼을 통해 다양한 데이터들을 송/수신할 수 있게 되었다.

디지털 신호의 특징

  • 디지털 신호는 1로 표현하고 싶을 땐 특정 전압 이상을 가하고, 0으로 표현하고 싶을 땐 특정 전압의 미만로 가해 표현한다.
  • 즉, 15V라고 가정할 때 1로 표현하고 싶으면 5V 이상의 전압을 가하고, 0으로 표현하고 싶을 땐 5V 미만의 전압을 가하게 된다.
  • 디지털 신호 그래프의 0은 끊어진 것처럼 보이지만 사실 끊어진 게 아니라 특정 전압 미만이기 때문에 0으로 그래프상 표시한 것뿐이다. 실제론 계속 전류는 흐른다.

아날로그 신호와 디지털 신호를 합치면

Digital And Analog

  • 위 그림처럼 컴퓨터는 특정 전압(예 5V)을 기준으로 미만은 0으로, 이상은 1로 인식하여 2진수의 데이터를 송/수신하게 된다.
  • 그렇게 송/수신한 데이터를 가지고 어떠한 기능((예) 해석, 출력, 등등)을 실행하게 된다.

아날로그 신호의 데이터화

Data Collection Graph

1byte8bit이다.”

  • 위 그래프는 1초 동안 발생한 아날로그 신호를 디지털 신호로 해석한 그래프이다.
  • 위 그래프에서 볼 수 있듯이 200ms1btye의 데이터를, 100ms2btye의 데이터를, 50ms3btye의 데이터를 수집할 수 있는 것을 볼 수 있다.
  • 1초의 시간을 촘촘히 측정할 수 있게 된다면 더 많은 양의 데이터를 주고받을 수 있게 된다.
  • 또한, 조금 더 촘촘히 많은 데이터를 수집할 수 록 아날로그 데이터에 굉장히 가까워진다.
  • 하지만, 아무리 아날로그 신호디지털 신호로 바꾸어도 어쩔 수 없이 데이터 왜곡은 생기기 마련이다.

가정에서 많이 사용하는 CAT5.E Cable

CAT.5E Cable

CAT.5E vs CAT.6 차이

CAT.5E vs CAT.6 Cable

“bps = bit per second(1초당 몇 비트를 전송하는가?) 즉, 100메가 인터넷 속도는 100Mbps이고 이는 1초에 100Megabit 즉, 12.5MB(메가 바이트)의 데이터를 다운로드할 수 있다는 이야기다.
또한 100MHz(100 메가헤르츠) 주파수의 전파는 1초에 100만 번 진동한다는 의미이다.”

  • 1초에 100MHz의 데이터 전송이 가능한 케이블이다.
  • 참고로, 1초에 진동하는 주파수가 많을수록 주파수가 높다고 표현을 한다.
  • 주파수가 높을수록 빛과 같이 직진성이 강해서 특정 방향으로 송신하는데 유리하고 많은 정보를 실을 수 있다는 장점이 있다.
  • 하지만, 비가 오거나 안개가 많이 낀 날은 공기 중에 물방울과 수증기가 많아지기 때문에 전파가 흡수되어 멀리 전파될 수 없다는 단점이 있다.
  • 반대로 주파수가 낮은 전파는 직진성은 약하지만 장애물을 뛰어넘는 특성이 있어 넓은 지역을 커버하는데 유리다. 하지만 주파수가 낮을수록 실을 수 있는 데이터 정보량은 적다.
  • 위에서 예시로 든 50ms(1초에 2번의 주파수)와 1초에 100MHz(1초에 1,000,000번 - 100만 번의 주파수)의 데이터 수집 양에 엄청난 차이를 느낄 수 있다.
    • 참고로, “현재 통신사에서 1기가 인터넷을 최대 속도로 서비스하고 있는 상황에서 케이블의 종류에 따른 속도의 차이는 없다.”
    • 다만, 차후 2.5G5G의 속도가 상용화되면 지금의 1Gbps보다 빠른 속도를 제공받을 수 있다는 이야기.

위 전파(전자기파) 신호를 담당하는 하드웨어 PHY 칩

Phy 칩

  • Physical Layer는 하드웨어적으로 구현되어 있다.
  • PHY 칩아날로그 신호디지털 신호(decoding)로,
  • 디지털 신호아날로그 신호(encoding)로 변환해 주는 하드웨어이다.

그래서 결국 Physical Layer란?

  • 물리적인 전선Phy 칩을 통해 01의 나열된 신호를 통신하는 계층이다.
  • 01의 나열된 디지털 신호아날로그 신호로 바꾸어 전선을 통해 송신하게 된다. -> encoding
  • 아날로그 신호가 들어오면 01의 나열로 해석한다. -> decoding
  • 물리적으로 연결된 두 대의 컴퓨터가 01의 나열을 주고받을 수 있게 해주는 모듈(module)이다.

Reference

[Routine] 6 주차 시작!

[Routine] 6 주차 시작!

2023년 2월 20일 부터 2월 26일 까지의 나의 루틴.

#목차

2023-02-20

2023-02-20

  • 오늘도 어김없이 영한 님의 인강을 들으면서 출근하였다.
  • 출근하자마자 이제 1주일 남은 독학사 공부를 1시간 하였다.
  • 현대사회와 윤리 과목인데 그나마 정의란 무엇인가소크라테스 익스프레스를 읽어서 생소한 이름은 그나마 줄어든듯 하다.
  • 1시간 현대사회와 윤리 과목을 공부하고, 이것이 자바다 공부를 하였다.

컬렉션 자료구조(List)

  • 자바는 자료구조(Data Structure)를 바탕으로 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 관련된 인터페이스클래스들을 java.util 패키지에 포함시켜 놓았다.
  • 이들을 총칭해서 컬렉션 프레임워크(Collection Framework)라고 부른다.

collection

“점선(- - -) : 구현 클래스, 실선(—-) : 상속 관계이다.”

  • 인터페이스별 사용할 수 있는 컬렉션의 특징
인터페이스 분류특징구현 클래스
CollectionList-순서를 유지하고 저장
-중복 저장 가능
ArrayList, Vector, LinkedList
Set-순서를 유지하지 않고 저장
-중복 저장 안됨
HashSet, TreeSet
Map-키와 값으로 구성된 엔트리 저장
-키는 중복 저장 안됨
HashSet, Hashtable, TreeMap, Properties

List Collection

  • List 컬렉션은 객체를 인텍스로 관리하기 때문에 객체를 저장하면 인덱스가 부여되고 인덱스로 객체를 검색, 삭제할 수 있는 기능을 제공.
기능메서드설명
객체
추가
boolean add(E e)주어진 객체를 맨 끝에 추가
void add(int index, E element주어진 인덱스에 객체를 추가
set(int index, E element)주어진 인덱스의 객체를 새로운 객체로 바꿈
객체
검색
boolean constains(Object o)주어진 객체가 저장되어 있는지 여부
E get(int index)주어진 인덱스에 저장된 객체를 리턴
isEmpty()컬렉션이 비어 있는지 조사
int size()저장되어 있는 전체 객체 수를 리턴
객체
삭제
void clear()저장된 모든 객체를 삭제
E remove(int index)주어진 인덱스에 저장된 객체를 삭제
boolean remove(Object o)주어진 객체를 삭제

Continue with List Collection Commit

ArrayList
  • ArrayList에 객체를 추가하면 내부 배열에 객체가 저장된다.
  • 일반 배열과의 차이점은 ArrayList제한 없이 객체를 추가할 수 있다는 것.

ArrayList

List 컬렉션은 객체 자체를 저장하는 것이 아니라 객체의 번지를 저장한다. 또한 동일한 객체를 중복 저장할 수 있는데, 이 경우에는 동일한 번지가 저장된다. null 또한 저장이 가능하다.”

import java.util.List;

public class ArrayList {
  public static void main(String[] args) {
    List<E> list = new ArrayList<E>();  // E에 지정된 타입의 객체만 저장
    List<E> list = new ArrayList<>();   // E에 지정된 타입의 객체만 저장
    List list = new ArrayList();        // 모든 타입의 객체를 저장
  }
}
  • ArrayList 컬렉션에 객체를 추가하면 인덱스 0번부터 차례대로 저장된다.
  • 특정 인덱스의 객체를 제거하면 바로 뒤 인덱스부터 마지막 인덱스까지 모두 앞으로 1씩 당겨진다.
  • 마찬가지로 특정 인덱스에 객체를 span style=”color:#ff8080”>삽입</span>하면 해당 인덱스부터 마지막 인덱스까지 모두 1씩 밀려난다.

ArrayList

“따라서 빈번한 객체 삭제와 삽입이 일어나는 곳에서는 ArrayList를 사용하는 것은 바람직하지 않다. 대신 이런 경우라면 LinkedList를 사용하는 것이 좋다.”

Continue with ArrayList Commit

  • 퇴근 후 역시 영한 님의 인강을 들으면서 퇴근 하였다.
  • 퇴근하면서 들은 생각이 인강을 듣기만 하지 말고 코드로 옮겨서 정리해야겠다 라는 생각이 들었다.
  • 집에 와서 밥을 먹고 운동한 후에 오전에 공부한 내용을 정리하였다.
  • markdown 문법 중 테이블 컬럼또는 행을 병합하던 중 문제가 발생했는데 합쳐지지가 않는 것이었다.
  • 1시간의 사투 후 결국 아래와 같이 방법을 찾아냈는데 바로 jekyll-spaceship라는 플러그인을 설치하면 잘 되었다.
# file: "Gemfile"
# If you have any plugins, put them here!
group :jekyll_plugins do
  gem 'jekyll-spaceship'
end
# file: "_config.yml"
plugins:
  - jekyll-spaceship
# file: "_config.yml"
# Where things are
jekyll-spaceship:
  # default enabled processors
  processors:
    - table-processor
    - mathjax-processor
    - plantuml-processor
    - mermaid-processor
    - polyfill-processor
    - media-processor
    - emoji-processor
    - element-processor
  mathjax-processor:
    src:
      - https://polyfill.io/v3/polyfill.min.js?features=es6
      - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
    config:
      tex:
        inlineMath:
          - ['$','$']
          - ['\(','\)']
        displayMath:
          - ['$$','$$']
          - ['\[','\]']
      svg:
        fontCache: 'global'
    optimize: # optimization on building stage to check and add mathjax scripts
      enabled: true # value `false` for adding to all pages
      include: []   # include patterns for math expressions checking (regexp)
      exclude: []   # exclude patterns for math expressions checking (regexp)
  plantuml-processor:
    mode: default  # mode value 'pre-fetch' for fetching image at building stage
    css:
      class: plantuml
    syntax:
      code: 'plantuml!'
      custom: ['@startuml', '@enduml']
    src: http://www.plantuml.com/plantuml/svg/
  mermaid-processor:
    mode: default  # mode value 'pre-fetch' for fetching image at building stage
    css:
      class: mermaid
    syntax:
      code: 'mermaid!'
      custom: ['@startmermaid', '@endmermaid']
    config:
      theme: default
    src: https://mermaid.ink/svg/
  media-processor:
    default:
      id: 'media-{id}'
      class: 'media'
      width: '100%'
      height: 350
      frameborder: 0
      style: 'max-width: 600px; outline: none;'
      allow: 'encrypted-media; picture-in-picture'
  emoji-processor:
    css:
      class: emoji
    src: https://github.githubassets.com/images/icons/emoji/
  • 얼른 커밋 하고 독학사 공부해야겠다…😭

2023-02-21

컬렉션 자료구조(Vector, LinkedList)

List Collection

2023-02-21

  • 오늘도 영한 님의 인강을 들으면서 출근을 했다.
  • 어제 자기 전에 markdown 테이블 병합한 걸 보고 싶어 빌드 된 나의 블로그를 확인해 보았는데, 결론적으론 나의 local쪽에서만 가능한 것으로 확인되었다.
  • 해당 jekyll-spaceship만 봐도 결국 <table></table> 태그를 사용하여 테이블 병합을 하고 커밋 하였다..
  • 뭔가 좀 아쉽긴 하다….🤨
  • 수정을 하고 바로 독학사 공부를 하였다. 그리고 8시 30분부터 이것이 자바다를 공부하였다.
  • 어제 오전에 공부한 ArrayList커밋Vector를 공부하기 시작했다.
Vector
  • VectorArrayList와 동일한 내부 구조를 가지고 있다.
  • 차이점Vector동기화된(synchronized) 메서드로 구성되어 있기 때문에 멀티 스레드가 동시에 Vector() 메서드를 실행할 수 없다는 것이다.
  • 그렇기 때문에 멀티 스레드 환경에서 안전하게 객체를 추가 또는 삭제할 수 있다.

Vector

import java.util.List;
import java.util.Vector;

public class Vector {
  public static void main(String[] args) {
    List<E> list = new Vector<E>(); // E에 지정된 타입의 객체만 저장
    List<E> list = new Vector<>();  // E에 지정된 타입의 객체만 저장
    List list = new Vector();       // 모든 타입의 객체를 저장
  }
}

Continue with Vector Commit

LinkedList
  • LinkedListArrayList와 사용 방법은 동일하지만 내부 구조는 완전히 다르다.
  • ArrayList는 내부 배열에 객체를 저장하지만, LinkedList는 인접 객체를 체인처럼 연결해서 관리한다.

LinkedList

  • LinkedList는 특정 위치에서 객체를 삽입하거나 삭제하면 바로 앞뒤 링크만 변경하면 되므로 빈번한 객체 삭제와 삽입이 일어나느 곳에서는 ArrayList보다 좋은 성능을 발휘한다.

LinkedList

import java.util.List;
import java.util.LinkedList;

public class LinkedList {
  public static void main(String[] args) {
    List<E> list = new LinkedList<E>(); // E에 지정된 타입의 객체만 저장
    List<E> list = new LinkedList<>();  // E에 지정된 타입의 객체만 저장
    List list = new LinkedList();       // 모든 타입의 객체를 저장
  }
}

Continue with LinkedList Commit

2023-02-22

2023-02-22

  • 어제 회사에서 끝나고 차장님과 사원 한 분이랑 남아서 스타크래프트를 했다. 오랜만에 하니까 힘이 든다. 눈도 아프고…😂
  • 오자마자 독학사 공부를 1시간 하였다. 망한 거 같다… 시험이 이번 주 일요일인데…😇
  • 그리고 나머지 1시간은 어제저녁 늦게 집에 도착하는 바람에 정리하지 못한 List Collection, ArrayList, Vector, LinkedList를 정리하였다.
  • 정리를 하고 나니 업무 시간이다…😂
  • 퇴근하기전 영한 님의 로드맵을 보면 두 가지가 있다.
  • 스프링 완전 정복을 먼저 듣기로 하였다.
  • 왜냐하면 스프링 부트와 JPA를 보기 전에 스프링에 대해 좀 더 이해하고 넘어가고 싶었다.
  • 그렇게 퇴근 후 독학사 시험이 얼마 남지 않아서 독학사 공부만 하였다.

2023-02-23 스터디 발표날

2023-02-23

  • 오늘도 어김없이 영한 님의 인강을 듣고 출근하였다.
  • 인강이 좀 새롭게 느껴지는 게 스프링의 역사를 알려주셔서 개인적으로 역사를 좋아하는 한 사람으로서 더 재미있게 느껴지는 거 같다. 역시..👏
  • 출근해서 어제 회사에서 front 단이 JSP로 되어있는 걸 Vue로 마이너그레이션 작업 중인 프로젝트를 회사 gitlab에 올리기 전에 테스트 후 커밋 하였다.
  • 파일이 생각보다 많아서 오래 걸릴 줄 알고 컴퓨터를 켜 놓고 커밋하고 퇴근했는데 생각보다 얼마 걸리지 않아서 괜히 걱정했구나 싶었다.😅
  • 그리고 또 독학사 공부를 시작하였다…………..😭

스터디 발표

  1. asd - 다형성

  2. 코드는 지우개로 지우게 - 인터페이스 구현

  3. thisiswoo - OpenID


  • 퇴근 역시 영한 님과 함께 한 후 집에 도착해서 운동 후 밥을 먹고 씻고 나와서 블로그 내용을 정리하였다.
  • OpenID 주제로 발표를 하는데 잘못된 내용이 있어 ppt 자료를 수정하였다.
  • 수정 내용은 OAuth2.0을 OpenID 2.0으로 잘못 표기한 것이다.
  • 또한 나의 루틴 포스트에 Continue withBack to link를 걸어 이전/이후 포스트들로 갈 수 있게 추가 하였다.
  • 커밋 후 독학사 공부하자…😭

2023-02-24

2023-02-24

  • 오늘도 어김없이 영한 님과 출근하는데 오늘은 SOLID를 배웠다. 약 1년 전 쯤 스프링을 공부하면서 배웠던 건데 내가 많이 잊고 있었다는 사실을 깨달았다.
  • SRP: 단일 책임 원칙(Single Responsibility Principle) -> 한 클래스는 하나의 책임만 가져야 한다.
  • OCP: 개방-폐쇄 원칙(Open/closed Principle) -> 소프트웨어 요서는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
  • LSP: 리스코프 치환 원칙(Liskov Substitution Principle) -> 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바뀔 수 있다.
  • ISP: 인터페이스 분리 원칙(Interface Segregation Principle) -> 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
  • DIP: 의존관계 역전 원칙(Dependency Inversion Principle) -> 프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안된다.” 의존성 주입은 이 원칙을 따르는 방법 중 하나다.
  • 다음에 SOLID에 대해 예제와 함께 포스팅 해야 겠다는 생각이 들었다.
  • 그리고 독학사를 공부하였다… 얼른 시험을 보고 싶다는 생각밖에 안든다…😭
  • 퇴근 역시 영한 님과 함께 하는데 SOLID가 잘 이해가 안되는 부분이 이써서 몇번을 돌려 보았다.
  • 결국 코드를 직접 작성해 보는게 좋을 듯하다.
  • 이번 주 일요일 까지는 독학사 공부를 위해 조금만 참자…😭

2023-02-25

  • 독학사……. 얼른 끝났으면 좋겠다.. 내일이다….

2023-02-26

  • 드디어 끝이 났다….🥳
  • 이젠 내가 하고 싶은 공부 해야겠다!
  • 일단 쉬면서 그동안 책 읽었던 것들을 정리해야겠다.

Reference

Back to [Routine] 5 주차 시작!

Continue with [Routine] 7 주차 시작!

[마이그레이션] 내가 회사 프로젝트 마이그레이션을 vue2가 아닌 vue3로 선택한 이유

[마이그레이션] 내가 회사 프로젝트 마이그레이션을 vue2가 아닌 vue3로 선택한 이유

#목차

내가 회사 프로젝트 마이그레이션을 vue2가 아닌 vue3로 선택한 이유

  • 작년 12월 말쯤, 회사에서 기존 프로젝트를 앞으로 크게 리뉴얼 할 예정이라는 이야기를 들었다.
  • 내가 왜 vue3를 택했는지 블로그에 포스팅해야겠다고 생각하고 있었다.
  • 조만간.. 곧.. 포스팅.. 해야지… 하지만… 마이그레이션과 나의 부족한 코딩 실력…이 발목을 잡았다.
  • 머리를 쥐어짜며 마이그레이션 작업을 하던 중 거의 마무리 단계에 이르러서 드디어! 블로그에 포스팅하게 되었다.

발단

  • 위에서 얘기했듯이 작년 12월 말쯤, 회사에서 기존 프로젝트를 앞으로 크게 리뉴얼 할 예정이라는 이야기를 들었다.
  • 회사의 2~3개의 프로젝트가 vue2.x 버전 대로 회사 내부 시스템을 vue2.x로 개발하기도 하였다.
  • 그러던 중 기존 프로젝트를 vue로 마이그레이션 한다고 하여 vue에 대해 비교 분석하여 제출하라고 하였다.
  • 그래서 나와 신입 한 분과 함께 vue에 대해 조사를 하였다.
  • 기존에 vue3에 대해 개인적으로 코지 코더님의 인강을 보면서 공부를 했고 사이드 프로젝트를 해본 경험이 있어 낯설진 않았다.
  • 하지만 vue2에 대해서는 유지 보수하는 정로로만 하는 실력이었다.

전개

  • 그렇게 신입 사원분과 함께 vue2와 vue3의 차이점, 장/단점, 그리고 테마, framework 등을 비교하여 분석 후 ppt 자료에 정리하여 보고하였다.
  • 간략한 정리 내용은 아래와 같다.

vue3.2 성능 개선(비교 vue2.x)

  • Vue.js의 창시자 Evan You공식 블로그에서 그 내용을 알 수 있다.
    1. More efficient ref implementation (~260% faster read / ~50% faster write)
    2. ~40% faster dependency tracking
    3. ~17% less memory usage
  • 구글 번역기를 그대로 돌려보면 아래와 같이 성능 개선을 하였다고 한다.
    1. 보다 효율적인 ref 구현(최대 260% 더 빠른 읽기/ 최대 50% 더 빠른 쓰기)
    2. 최대 40% 더 빠른 종속성 추적
    3. 메모리 사용량 최대 17% 감소
  • 또한, 다른 framework(react, angular 등)들 중에서 성능 부분이 빠르다는 것을 볼 수 있다.

vue2.xx vs vue3.2의 lifecycle hook 차이

  • 나의 포스팅 Vue.js 라이플사이클 이해하기를 참고하면 좋을듯하다.
  • 결국 Option API보다 Composition API의 사용으로 동일한 코드를 리팩토링 한 결과 코드의 사용량이 많이 줄 수 있게 되었다.
  • 또한, 동일한 논리적 문제와 관련된 코드가 어떻게 그룹화 되었는지 아래 그림을 통해 확인할 수 있다.

Options API를 Composition API로 리팩토링한 결과

vue2.xx vs vue3.2 npm 다운로드 수

  • 내가 처음 vue를 공부했을 때(2022년 12월 말)쯤 캡틴 판교 님의 Can I use … Vue 3? 영상을 보게 되었다.
  • 캡틴 판교 님의 영상을 보기 전 이미 [코지 코더] 님의 vue3 인강을 결제해 놓은 상태라 어쩔 수 없이 vue3 버전을 공부하였지만 그래도 나는 vue3가 조금 더 쉽게 다가왔다.(개인적으로 설명도 좋으셨다고 생각한다.)
  • 내가 인강을 들을 때만 해도 vue3의 다운로드 수는 그렇게 높지가 않았던 걸로 기억한다.

캡틴 판교 님의 vuejs 2.x vs 3.x 비교 영상 중 npm 다운로드 수

(2023년 4월 3일 기준)

  • 2021년 9월 5일 기준 : 약 17배가량의 다운로드 수
  • 2023년 4월 3일 기준 : 약 3.8배가량의 다운로드 수
  • vue3 초창기 3.x 대 라이브러리가 지원하지 않는 것이 굉장히 많아 아무래도 3.x 대보단 안전하고 풍부한 라이브러리를 제공하는 2.x 대를 많은 회사와 사람들이 선호하는 것을 확인할 수 있다.
  • 하지만 지금은 공식 문서의 주소나, vue3를 기준으로 한 vue-router, vuex 라이브러리 버전이 설치된다.

회사의 장기 프로젝트

  • 내가 vue3.x 대를 선택한 이유는 회사의 장기적 계획도 한 몫하였다.
  • 지금 신규 프로젝트를 계획하고 진행함에 있어 대표님께서 앞으로의 계획을 말씀해 주셨는데, 그 계획 중 개발자 시선으로 보자면, 다량의 트래픽이 발생한다는 것이다.
  • 물론, 해당 프로젝트가 잘 안될 수도 있다. 혹은 기획에서 망가질 수도 있다. 하지만, 나는 그래도 위 성능 개선에 초점을 두고 조금 더 나은, 조금 더 빠른 성능의 퍼포먼스를 적용하고 싶었다.

나의 욕심과 선례

  • 또 하나의 이유는 나의 욕심이다.
  • 내가 vue3로 하고 싶었다. 물론 나의 경력이(2023년 2월 기준 - 1년 3개월)이라는 짧은 경력에도 도전하고 싶었다.
  • 왜냐하면 회사에는 기존에 2~3개의 프로젝트가 2.x 대의 vue 프로젝트이다.
  • 나는 좋던 나쁘던 선례를 남기고 싶었다.
  • 좋은 선례는 2.x 대 뿐만 아니라 3.x의 퍼포먼스와 코드 작성 방법 들…
  • 나쁜 선례는 내가 작성하고 이끌어 나간 진행 방향의 잘못된 코드와 선례들을 통해 다른 직원들이 이렇게 짜면 안 되겠다는 그나마 희망적인 선례를 남기고 싶었다.

결말

  • 결국 나의 욕심?으로 인해 vue3 프로젝트로 확정되어 마이그레이션 작업 중이다.
  • 마이그레이션 작업하면서 많이 실패하고, 선배 개발자분들에게 많이 여쭈어보고, 많이 검색해 보고, 많이 공부한 거 같다. 물론 그래도 부족한 건 사실이다.!
  • 그래도 내가 프로젝트를 주도적으로 이끌어 나갈 수 있는 기회는 사실 많이 없는 거 같다. 특히나 연차가 얼마 안 되는 나에게 이런 기회는 흔치 않는 거 같다.
  • 이렇게 기회를 준 차장님께 고마운 마음이 든다.
  • 물론 아직 프로젝트가 끝나지 않았고, 차장님도 망할 수 있다는 생각을 하셨는지 안 하셨는지 모르지만 그래도 날 믿고 맡겨주신 차장님께 감사하다.
  • 이 프로젝트가 망하면 선배 개발자분들이 계시니까 보험이 있으니 맡겨주신 거 일 수도 있다…^^;;
  • 망하지 않게 내가 잘 이끌어 나가야지…!!!

References

[Routine] 5 주차 시작!

[Routine] 5 주차 시작!

2023년 2월 13일 부터 2월 19일 까지의 나의 루틴.

#목차

2023-02-13

2023-02-13

  • 오늘 아침도 어김없이 영한님과 함께 출근하였다.
  • 출근 후 오늘 오전에는 내가 2020년부터 읽었던 책들을 블로그에 올리는 기초작업을 하였다.
  • 2020년도에는 읽었다라고만 도서 기록 앱으로 등록하고 독후감을 작성하지 않았다.
  • 확실히 기록하는 습관이 무엇이든 기억에 오래 남는다는 것을 다시 한번 느끼게 된 거 같다.

2023-02-14

  • 오늘은 정기검진을 받는 날이라 아침 일찍 CT와 위내시경을 하기 위해 오전 7시까지 구로 고대 병원에 도착했다.
  • 오전 7시에 채혈검사를 하고 8시쯤에 심전도 검사하고 10시쯤에 CT 촬영하고 11시 좀 넘어서 위내시경 검사를 했다.
  • 중간에 대기 시간들이 많아 영한 님의 인강을 들으면서 대기했다.
  • 정기 검진이 끝나고 치과 가서 정기검진을 받고 집에 들어오니까 오후 3시가 됐다.
  • 너무 배가 고파서 치킨을 사 와서 먹고 그 자리에서 2시간가량을 잠이 든 거 같다.
  • 일어나서 다시 저녁 먹고 블로그 정리하다가 자려고 한다.
  • 요새는 내가 읽었던 책들을 포스팅 작업을 하고 있다.
  • 생각보단 많이 읽지 못한 거 같아 아쉽긴 하다.
  • 그래도 이번 연도에는 기술서들을 많이 읽을 예정이다. 내가 개인적으로 좋아하는 책들은 기술서를 다 읽고 읽을 예정이다.
  • 내일을 위해 블로그 작업을 조금만 하고 자야겠다.😪

2023-02-15

2023-02-15

  • 오늘도 어김없이 영한 님과 함께 출근을 하고 회사 도착하자마자 이것이 자바다 공부를 하였다.
  • 과거 포스팅들은 공부한 얘기만 들어가 있어 내가 정확히 그때 공부를 어디서부터 어디까지 무엇을 했는지 기억이 나질 않았다.
  • 그래서 오늘부터는 내가 한 공부를 기록하기로 하였다. 그것이 더 머릿속에 오래 남을 거 같기 때문이다.

멀티 스레드

yeild()

yeild()를 호출한 스레드는 실행 대기 상태로 돌아가고, 다른 스레드가 실행 상태가 된다.”

  • 스레드가 처리하는 작업은 반복적인 실행을 위해티 for문이나 while문을 포함하는 경우가 많다.
  • 무의미한 반복을 하는 경우가 있을 수 있는데 이때 Threadyield()메서드를 제공한다.

Continue with yeild() Commit

스레드 동기화 메서드 및 블록 선언

스레드가 사용중인 객체를 다른 스레드가 변경할 수 없도록 하려면 스레드 작업이 끝날 때까지 객체에 잠금을 걸면 되는데, 이를 위해 Java는 synchronized 메서드와 블록을 제공한다.”

public class Synchronized {
    // example 1
    public synchronized void mathodA() {
        // 단 하나의 스레드만 실행하는 영역
    }
    // example 2
    public void methodB() {
        // 여러 스레드가 실행할 수 있는 영역
        synchronized (공유객체) {
            // 단 하나의 스레드만 실행하는 영역
        }
        // 여러 스레드가 실행할 수 있는 영역
    }
}

Continue with synchronized Commit

wait()과 notify()를 이용한 스레드 제어

경우에 따라서는 두 개의 스레드를 교대로 번갈아 가며 실행할 때도 있다. 정확한 교대 작업이 필요할 경우, 자신의 작업이 끝나면 상대방 스레드를 일시 정지 상태에서 플어주고 자신은 일시 정지상태로 만들면 된다..”

  • 한 스레드가 작업을 완료하면 notify() 메소드를 호출해서 일시 정지 상태에 있는 다른 스레드를 실행 대기 상태로 만들고
  • 자신은 두 번 작업을 하지 않도록 wait() 메소드를 호출하여 일시 정지 상태로 만든다.

Continue with wait(),notify() Commit


  • 퇴근 역시 영한님과 함께 하며 집에 와서 홈트와 오늘 공부한 포스팅 작업, 그리고 books log 작업을 하였다.

2023-02-16

2023-02-16

멀티 스레드

스레드 안전 종료

  • 스레드는 자신의 run() 메서드가 모두 실행되면 자동적으로 종료되지만, 경우에 따라서는 실행 중인 스레드를 즉시 종료할 필요가 있다.
  • 유튜브 같은 동영상을 끝까지 보지 않고 사용자가 멈춤을 요구하는 경우이다.
  • 스레드를 안전하게 종료하는 방법은 사용하던 리소스들을 정리하고 run() 메서드를 빨리 종료하는 것.
  • 주로 조건 이용 방법interrup() 메서드 이용 방법을 사용한다.

조건 이용

  • 스레드가 while 문을 반복 실행할 경우, 조건을 이용해서 run() 메서드의 종료를 유도할 수 있다.
  • 다음 코드는 stop 필드 조건에 따라서 run() 메서드의 종료를 유도한다.
    public class XXXThread extends Thread {
      private boolean stop;   // stop 필드 선언
        
      public void run() {
          while (!stop) { // stop이 true가 되면 while 문을 빠져나간다.
              // 스레드가 반복 실행하는 코다;
          }
          // 스레드가 사용한 리소스 정리
      }// 스레드 종료
    }
    

Continue with Conditional Utilization Thread Commit

interrupt() 메서드

  • interrupt() 메서드는 스레드가 일시 정지 상태에 있을 때 InterruptedException 예외를 발생시키는 역할을 한다.
  • 이것을 이용하면 예외 처리를 통해 run() 메서드를 정상 종료시킬 수 있다.
    • 스레드가 실행 대기/실행 상태일 때에는 interrupt() 메서드가 호출되어도 InterruptException이 발생하지 않는다.
  • 그러나 스레드가 어떤 이유로 일시 정지 상태가 되면, InterruptException예외가 발생한다.
  • 그래서 짧은 시간이나마 일시 정지를 위해 Thread.sleep(1)을 사용한 것.
  • 일시 정지를 만들지 않고도 interrupt() 메서드 호출 여부를 알 수 있는 방법이 있다.
  • Threadinterrupted()isInterrupted() 메서드는 interrupt() 메서드 호출 여부를 return한다.
    boolean status = Thread.interrupted();
    boolean status = objThread.isInterrupted();
    
    // file: "InterruptPrintThread.java"
    public class InterruptPrintThread extends Thread {
      public void run() {
          try {
              while (true) {
                  System.out.println("실행 중");
                  // 방법 1. 일시 정지를 만듦 (InterruptedException 이 발생할 수 있게)
                  Thread.sleep(1);  
                  // 방법 2. interrupted() 메서드를 통해 interrupt() 메서드가 호출 되었다면 while 문을 빠져 나가게
                  if (Thread.interrupted()) {
                      break;
                  }
              }
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          System.out.println(("리소스 정리"));
          System.out.println(("실행 종료"));
      }
    }
    
    // file: "InterruptExample.java"
    public class InterruptExample {
      public static void main(String[] args) {
          Thread thread = new InterruptPrintThread();
          thread.start();
            
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e ) {
              e.printStackTrace();
          }
            
          thread.interrupt(); // interrupt() 메서드 호출 
      }
      // 결과 -------------------------------
      // 실행 중
      // ...
      // java.lang.InterruptedException: sleep interrupted
      //	at java.base/java.lang.Thread.sleep(Native Method)
      //	at ch14.multi_thread.InterruptPrintThread.run(InterruptPrintThread.java:8)
    }
    

Continue with Interrupt Thread Commit

데몬 스레드

  • 데몬 스레드는 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드.
  • 주 스레드가 종료되면 데몬 스레드도 따라서 자동 종료된다.
  • 스레드를 데몬으로 만들기 위해서는 주 스레드가 데몬이 될 스레드의 setDaemon(true)를 호출하면 된다.
  • 다음 예를 보면 메인 스레드는 주 스레드, AutoSaveThread는 데몬 스레드가 된다.
    public class DaemonExample {
      public static void main(String[] args) {
          AutoSaveThread thread = new AutoSaveThread();
          thread.setDaemon(true);
          thread.start();
          // ...
      }
    }
    

  • 오후에는 이직한 직원과 오랜만에 만나서 저녁을 먹고 집에 들어왔다.
  • 10시까지 수다를 열심히 떨고 각자 집에 들어갔다.😪

Continue with Daemon Thread Commit

2023-02-17 스터디

2023-02-17

멀티 스레드

스레드 풀⭐️⭐️⭐️⭐️⭐️

  • 병렬 작업 처리가 많아지면 스레드의 개수가 폭증하여 CPU가 바빠지고 메모리 사용량이 늘어난다.
  • 이에 따라 애플리케이션의 성능 또한 급격히 저하된다.
  • 이렇게 병렬 작업 증가로 인한 스레드의 폭증을 막을면 스레드풀(ThreadPool)을 사용하는 것이 좋다.
  • 스레드풀은 작업 처리에 사용되는 스레드를 제한된 개수만큼 정해 놓고 작업 큐(Quere)에 들어오는 작업들을 스레드가 하나씩 맡아 처리하는 방식.
  • 작업 처리가 끝난 스레드는 다시 작업 큐에서 새로운 작업을 가져와 처리한다.
  • 이렇게 하면 작업량이 증가해도 스레드의 개수가 늘어나지 않아 애플리캐이션의 성능이 급격히 저하되지 않는다.
    1. 스레드풀에 작업 처리 요청
    2. 작업 큐(Queue)가 선입선출의 방식으로 비어있는 스레드에 작업 할당.
      • 이때, 가장 먼저 작업이 끝나 비어있는 스레드에 큐에있는 작업을 할당하게 된다.
    3. 스레드는 해당 작업을 처리
    4. 결과 전달
스레드풀 생성
메소드명(매개변수)초기 수코어 수최대 수
newCachedThreadPool()00Integer.MAX_VALUE
newFixedThreadPool(int nThreads)0생성된 수nThreads
// 정적 메서드로 호출하고 return하는 것은 ExecutorService의 구현객체이다.
// ExecutorService 인터페이스로 대입을 받아야 한다.
// 아래가 스레드 풀이라고 생각하면 된다.
public class createThreadPool {
  public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool(); // 정적 메서드로 호출 
    ExecutorService executorService = Executors.newCachedThreadPool(5); // 정적 메서드로 호출
  }
}
// 좀 더 구체적인 스레드 풀 생성
public class createDetailThreadPool {
  public static void main(String[] args) {
    ExecutorService threadPool = new ThreadPoolExecutor(
            3, // 코어 스레드 개수
            100, // 최대 스레드 개수
            120L, // 놀고 있는 시간
            TimeUnit.SECONDS, // 놀고 있는 시간 단위
            new SynchronousQueue<Runnable>() // 작업 큐
    );
  }
}
스레드풀 종료
  • 스레드풀의 스레드는 기본적으로 데몬 스레드가 아니기 때문에 main 스레드가 종료되더라도 작업을 처리하기 위해 계속 실행 상태로 남아있다.
  • 스레드풀의 모든 스레드를 종료하려면 ExecutorService의 다음 두 메서드 중 하나를 실행해야 한다.
리턴 타입메서드명(매개변수)설명
voidshutdown()현재 처리 중인 작업뿐만 아니라 작업 큐에 대기하고 있는 모든 작업을 처리한 뒤에 스레드풀을 종료
ListshutdownNow()현재 작업 처리 중인 스레드를 interrupt해서 작업을 중지시키고 스레드풀을 종료시킨다. 리턴값은 작업 큐에 있는 미처리된 작업(Runnable)의 목록이다.
작업 생성과 처리 요청
  • 하나의 작업은 Runnable 또는 Callable 구현 클래스로 표현한다.
  • Runnable의 run() 메서드는 리턴값이 없고, Callable의 call() 에서드는 리턴값이 있다.
Runnable 익명 구현 클래스Callable 익명 구현 클래스
new Runnable() {
  @Overrid
  public void run() {
   // 스레드가 처리할 작업 내용
  }
}
new Callable {
  @Overrid
  public T call() throws Exception {
   // 스레드가 처리할 작업 내용
   return T;
  }
}
  • call()의 리턴 타입은 Callable<T>에서 지정한 T타입 파라미터와 동일한 타입이여야 한다.
  • 작업 처리 요청을 위해 ExecurotService는 다음 두 가지 메서드를 제공한다.
리턴 타입메서드명(매개변수)설명
voidexecute(Runnable command)- Runnable을 작업 큐에 저장
- 작업 처리 결과를 리턴하지 않음
Futuresubmit(Callable task)- Callable을 작업 큐에 저장
- 작업 처리 결과를 얻을 수 있도록 Future를 리턴

Continue with ThreadPool Commit


스터디 발표

왕돼지티라노의 기록 - JPA 영속성 관리1

^.^ - 쿠키vs세션vs토큰vs캐시

자바스크립트 내장객체

  • String 객체
    • indexOf(), replace()
    • concat() : 2개 이상의 문자열을 하나의 문자열로 합침.
    • trim() : 문자열 앞,뒤 공백 제거
    • padStart()/padEnd() : 문자열 앞/뒤에 지정된 문자를 지정된 길이만큼 추가
    • charAt(), split()
    • startWith()/endsWith() : 해당 문자열로 시작/끝 되는지 확인.

  • 퇴근 역시 영한님의 인강을 들으면서 퇴근하고, 집에 도착하자마자 내가 읽은 책 포스팅 작업을 하였다.
  • 생각보다 많아 시간이 많이 걸릴거 같다..😂

2023-02-18

  • 오늘은 아침 9시에 일어났다.. 늦잠을 자버렸다…😅
  • 어제 정리하던 책 첫 포스팅을 작업하고 커밋 하였다.
  • 그리고 이번 달까지 이것이자바다를 끝낼 예정이며 다음 주 일요일에 독학사 시험이라 독학사 공부를 다시 1주일간 시작하려 한다…😂
  • 11시 30분까지 공부를 하고 여자친구를 만나 세종문화회관에서 열리는 뮤지컬 Cats 오리지널 내한 공연을 보러 갔다 왔다.
  • 너무 멋진 공연이었다. 다음엔 내가 예약해서 또 1층에서 공연을 보고 싶다. 뮤지컬은 1층에서 봐야 하는 걸 느껴 버렸다😄

2023-02-19

  • 오늘도 늦잠을 자서 9시 좀 넘어서 일어났다.
  • 이것이 자바다 잠깐 책을 읽고 대체로 쉬었다.
  • 어제 집에 12시 넘게 들어와서 오늘 조금 쉬고 싶었지만 그래도 조금이라도 공부를 하는게 맞는 거 같아서 책을 좀 봤다.
  • 내일을 위해 쉬면서 책을 좀 더 읽다가 자려고 한다..😴

Back to [Routine] 4 주차 시작!

Continue with [Routine] 6 주차 시작!

[Routine] 4 주차 시작!

[Routine] 4 주차 시작!

2023년 2월 6일 부터 2월 12일 까지의 나의 루틴.

#목차

2023-02-06

2023-02-06

  • 오늘 아침도 영한님과 함께 출근하였다.
  • 회사에 도착해서 금요일(2023-02-10)에 있을 발표 자료를 만들었다. 이번 주 주제는 OAuth이다.
  • 아직 많이 만들지 못해 오전 공부시간 내내 자료를 만들었다.
  • 퇴근을 어김없이 영한 님과 같이 퇴근하고 집에 가서 운동하고 밥 먹고 바로 11시 30분까지 발표 자료를 만들었다.
  • 생각보다 양이 많아 어떻게 할지 고민해 봐야겠다.

2023-02-07

2023-02-07

  • 오늘도 영한 님과 같이 출근 후 아침부터 이번 주 금요일(2023-02-10)에 있을 스터디 발표 자료를 만들었다.
  • 아직 준비된 게 많이 없어 생각보다 오래 걸리는 듯하다.
  • 요새 회사에서 스프링시큐리티를 적용 중인데 꽤 고생하고 있는 듯 하다.
  • 최근에 이렇게 진이 빠진 적은 없는 거 같은데 역시 한참 부족하다는 뜻 같다.

2023-02-08

2023-02-08

  • 오늘도 영환 님과 함께 출근 후 스터디 발표 자료를 만들었다.
  • 준비하는 량이 많아 생각보다 길어지고 있어 며칠 동안 계속 공부보다는 자료 모으고 발표 준비를 하였다.
  • 양이 너무 많아 OAuth와 OpenID의 주제였는데 이번 주는 OAuth만 발표하고 다음에 OpenID를 발표해야 하나 싶다.
  • 퇴근 후 역시 운동 후 책상에 앉아서 발표 준비를 하였다.
  • 9시.. 10.. 11시.. 12시… 12시 반…
  • 다행히도 거의 마무리 지어서 내일까지 하면 될 거 같다.

2023-02-09

2023-02-08

  • 오늘도 영한 님과 같이 출근하고 어제 저녁에 마무리 못한 포스트를 정리하였다.
  • 어제 저녁 늦게까지 자료 정리하고 남아 있는 부분을 정리하였다.
  • OAuth 부분은 다 정리하고 퇴근 후 집에 가서 OpenID 작업하면 될 거 같다.
  • 퇴근 후 나머지 OpenID를 정리하였다. 다음번 발표 자료까지 준비해서 마음에 여유가 생긴 기분이다.😙

2023-02-10 스터디 발표날

2023-02-08

  • 오늘은 오랜만에 이것이자바다만 공부하게 되었다.
  • 오랜만에 해서 그런지 개발 공부가 너무 반가웠다.
  • 공부한 내용을 커밋 하였다.

스터디 발표

  1. asd - 제어자
    • static 메서드는 사용하려면 클래스명.메서드명으로 사용 가능
  2. 코드는 지우개로 지우게 - 인터페이스
    • 인터페이스에 선언된 필드는 모드 public static final의 특징을 갖는다.
    • 필드 선언 시에 public static final을 생략하더라도 컴파일 시 자동적으로 붙는다.
    • 인터페이스에 선언된 추상 메소드는 모두 public abstract의 특성을 갖기 때문에 public abstract를 생략하더라도 자동적으로 컴파일 과정에서 붙게 된다.
    • Java8+ -> 디폴트 메소드( Default Method ) 추가
    • 디폴트 메소드는 인터페이스에 선언되지만 객체( 구현 객체 )가 가지고 있는 인스턴스 메소드라고 생각해야 한다.
    • 형태는 클래스의 인스턴스 메소드와 동일한데, default 키워드가 리턴 타입 앞에서 붙는다.
    • 디폴트 메소드는 public 특성을 갖기 때문에 public을 생략하더라도 자동적으로 컴파일 과정에서 붙게 된다.
  3. thisiswoo - OAuth

2023-02-11

  • 오늘은 오랜만에 엄청 오래 잤다…😂
  • 너무 오래 자서 머리가 아플정도로 잔거 같다..
  • 일어나서 학점은행제 중간고사 시험기간이라 3과목 시험을 보고 오늘 하루 일과를 끝냈다..
  • 내일 남은 나머지 과목 4가지 시험 보면 될거 같다.

2023-02-12

  • 오늘은 9시에 일어났다.
  • 일어나서 밥 먹고 바로 씻고 나와서 남은 중간고사 4과목 시험을 보았다.
  • 그리고 쉬면서 4주 차 루틴 포스트 작업을 정리하였다.
  • 내일도 하던 데로 일찍 가서 공부해야겠다.

Back to [Routine] 3 주차 시작!

Continue with [Routine] 5 주차 시작!

[Security] OpenID Connect

[Security] OpenID Connect

“해당 포스팅은 우아한Tech[10분 테코톡] 토닉, 후디의 인증과 인가 - 부족사회부터 소셜로그인까지을 참고하여 포스팅하였습니다. 영상을 제작해주신 우아한Tech토닉, 후디님에게 감사드립니다.”

#목차

OpenID Connect

OpenID Connect 개요

클라이언트의 단점

openid_outline1

  • 우리가 일반적으로 직접 인증기능을 구축하기 위해선 사용자로부터 ID/PW등과 같은 개인정보를 직접 제공 받아야 한다.
  • 그런데, 보안사고가 터지면 큰일이다…

사용자의 단점

openid_outline2

  • 사용자 또한 불편함을 가지고 있게 된다.
  • 지금 처럼 굉장히 많은 서비스를 이용하는 시대에서 각 서비스마다 ID/PW기억하고 있어야하는 불편함이 생긴다.

OpenID의 시작

openid_question

  • 이런 아이디어에서 OpenID가 시작 되었다
  • OpenID Foundation에서 추진하는 개방형 표준 및 분산 인증 프로토콜이다

OpenID의 장점

explan_openid

OpenID를 사용하면 새 비밀번호를 만들 필요 없이” 기존 계정을 사용하여 여러 웹사이트에 로그인할 수 있다.”

OpenID의 2가지 버전

openid_2version

  • OpenID도 크게 두 가지 주체로 나눌 수 있다
  • IdP : 구글, 카카오와 같이 OpenID 서비스를 제공하는 당사자
  • RP : 사용자를 인증하기 위해 IdP에 의존하는 주체

OpenID 버전

openid_version

“해당 포스트에서는 3세대 OpenID Connect(OIDC)를 포스팅

OpenID Connect 정의

explan_openid2

OpenID Connect 1.0은 OAuth2.0 프로토콜 위에 있는 간단한 ID 계층. 이를 통해 클라이언트는 REST와 유사한 방식으로 최종 사용자의 신원과 기본적인 프로필 정보를 얻을 수 있다”

OIDC와 OAuth2.0

openid_hierarchy

OIDC와 OAuth2.0의 목적 차이

oauth_vs_openid

OAuth2.0과 OpenID Connect목적 차이

  • OAuth2.0 목적 : Access Token을 발급받고 리소스에 접근하기 위해 발급
  • OpenID Connect 목적 : ID Token을 발급받고 ID Token으로부터 사용자 식별 정보를 얻기 위해 사용된다

ID Token

id_token

사용자 식별정보를 담고 있는 JWT토큰

id_token_payload

ID Token의 발급 방법

how_to_issue_id_token

ClientAuthorization ServerOAuth2.0 인증을 요청 할 때 Scope에 OpenID를 추가하면, ID Token을 받을 수 있다”

OAuth2.0의 단독 유저 식별의 문제점

openid_question2

OAuth2.0사용자에 대한 정보명시적으로 제공하지 않는다

different_oauth_openid

  • OAuth2.0을 통해서 발급받은 Access Token으로는 서버의 리소스는 접근 권한이 가능하지만, 발급받은 Access Token만으로는 사용자 정보 프로필획득 불가
  • OpenID Connect를 통해서 발급받은 ID Token으로는 서버의 리소스는 접근 권한이 불가능하지만, 발급받은 ID Token만으로는 사용자 정보 프로필획득 가능

유저 프로필 가져올 때

use_oauth

OAuth2.0만을 사용했을 땐, 통신이 두 번 발생

  1. Access Token요청할 때
  2. Access Token을 가지고 유저 프로필 정보요청할 때

use_openid

“반면, OpenID Connect를 사용하면 한 번의 통신으로도 유저 프로필 정보획득

  1. Access TokenID Token한 번에 요청하고 한 번에 전달받게 된다
  2. 이어서 후속적인 조치 없이 Client는 방금 전달받은 ID Token디코드 하여 유저 프로필 정보를 획득

Back to [Security] OAuth

Pagination