List 컬렉션

  • List컬렉션은 인덱스 순서로 저장이 되며 중복된 데이터가 저장이 가능하다. 
  • 구조적으로 데이터를 일렬로 늘여놓는 구조를 가진다.
  • 객체를 저장하면 인덱스가 자동으로 부여되고 부여된 인덱스를 통해 데이터의 검색 및 삭제가 가능

List컬렉션을 구성하는 대표적인 클래스들은 ArrayList,Vector,LinkedList 가있다.

 

List서 사용하는 메소드

 

ArrayList

  • ArrayList는 List 인터페이스를 구현한 클래스이다.
  • 설정된 저장 용량보다 많은 데이터가 들어오면 자동으로 용량이 늘어난다.

List<E> 객체명 = new ArrayList<E>([초기 저장용량]);

 초기 저장용량을 생각하면 기본적으로 10의 저장용량을 가진다. E는 제네릭 타입을 의미하는데 생략하면 Object 타입이된다. Object는 모든 데이터 타입을 저장 가능하지만 데이터를 추가하거나 검색할 때 형 변환을 해야 한다. 

  • 자료구조에는 주로 동일한 데이터 타입을 저자앟기 때문에 제너릭타입을 지정하는 것이 좋다.
  • 기본적으로 데이터를 추가 하거나 삭제할 경우에는 인덱스가 한 칸씩 뒤로 밀리거나 당겨진다.

Vector

ArrayList와 동일한 구조를 갖는다. 차이점이라면 Vector는 자동 동기화를 보장하므로 멀티 스레드 환경에서 안정적으로 사용이 가능하다. 하지만 단일 스레드에서는 ArrayList가 성능이 더 좋다. Vector를 생성하는 방법은 다음과 같다.

List<E> list = new vector<e>([초기용량,</e> 증가용량]);

 초기 용량과 증가 용량을 생략하면 기본 값인 0으로 설정된다.

Vector와 ArrayList의 차이점이면 자동동기화를 보장한다는거지만 동기화의 처리가 필요할때는 Vector보다 Collection, synchronizedCollection, synchronizedList,Map을 이용하는게 성능적으로 더낫다.

 

LinkedList

 List의 구현 클래스이므로 ArrayList나 Vector와 사용 방법은 동일하다. 하지만 구조는 다르게 구성되어있다. 위의 컬렉션들은 인덱스로 데이터를 관리하지만 LinkedList는 인접한 곳을 링크하여 체인처럼 관리한다.  LinkedList는 중간의 데이터를 삭제할 때 인접한 곳의 링크만을 변경하면 되기 때문에 중간에 데이터를 추가/삭제하는 경우 처리 속도가 빠르다.

ArrayList와 LinkedList 비교

 

List<E> list = new LinkedList<E>();

상황에 따라 적절한 컬렉션을 사용하면 될거같다. 찾아보니 vector의경우 요즘 JAVA에서는 잘안쓰이는 추세라고한다...

 

기본형

 boolean,char byte,short,int,long,float,double와 같이 계산을 할 수 있는 타입.

저장 공간에 값 자체를 저장함

기본형 변수의 타입

  • 정수 타입: byte (1byte), short (2byte), int (4byte), long (8byte)
  • 부동소수점 타입: float (4byte) , double (8byte)  
  • 부울 타입: boolean (1byte) // true,false 두 가지 값만 표현 
  • 문자 데이터 타입: char (2byte)

기본형 변수의 선언

정수 타입 

  • int age = 20;
  • long age = 20L;  —> Long type을 사용하기 위해선 반드시 붙여야 함

부동소수점 타입

  • double dot = 10.2 
  • float dot = 10.2F  —> float 타입을 사용하기 위해선 반드시 붙여야 함

 

 

변수 형변환

  • 확장 변환
    • 데이터 타입보다 더 큰 타입으로 변환되기 때문에, 값의 손실이 없다
  • 축소 변환
    • 데이터 타입보다 더 작은 타입으로 메모리 공간이 축소되기 때문에, 값의 손실이 생김
  • 데이터 변환 방법
    • 데이터 손실이 생기는 축소 변환에만 casting 필요 

                     ex) int a = (int)10.2F;

    • boolean을 제외한 7가지 기본형 간에는 서로간의 형변환이 가능

 

참조형

  • 기본형을 제외한 나머지 타입. String , StringBuffer ,List등 혹은 개인이 만든 클래스도 참조형 타입이 가능
  • 참조 값(주소)를 가지는 자료형
  • 자바 API에서 제공되거나 프로그래머에 의해서만들어진 클래스를 자료형으로 선언하는 경우
  • 참조변수는 클래스 이름을 가지고 만들 수있다. (Member mem;) ==> 변수의 타입이 기본형이 아닌것들은 모두 참조 변수

 

힙과 스택의 저장되는 메모리 차이

 

자바 메모리 관리 - 스택 & 힙

개요 Java 에서 메모리 관리는 어떻게 이루어지는지 알아보기 위함. Stack 과 Heap 영역 각 역할에 대해 알아본다. 간단한 코드예제와 함께 실제 코드에서 어떻게 Stack 과 Heap 영역이 사용되는지 살펴본다. Wrapper Class 와 Immutable Object 에 대해서도 살짝 알아본다. Garbage Collection 이 무엇인지도 아주 살짝 알아본다.

yaboong.github.io

위의 사이트서 자세하게 다루고있다.

 

== 과 Equals()의 차이점

 

1) 형태의 차이

 우선 가장 단순한 차이점은 형태의 차이이다

  • equals()는 메소드이다 --> 객체끼리 내용을 비교할 수 있도록 한다.
  • == 는 비교를 위한 연산자 이다.
  • equlas 메소드는 비교하고자 하는 대상의 내용 자체를 비교하지만
  • == 연산자는 비교하고자 하는 대상의 주소값을 비교한다.

   String a = "bbb";

   String b = a;

   String c = new String("bbb");

 

위 코드에서 보면 변수 b는 a를참조하고있어서 둘다 bbb를 가지고있다. 또한 변수 c도 문자열을 선언하여 bbb를 가지고있다.

변수 b는 a를 참조하고있어서 a의 주소값과 b의 주소값이 같고 c의 경우 문자열을 새로 선언해주었기 때문에 새로운 주소값을 할당받게되어 a,b 의 주소값가 다른 주소값을 가지게 된다.

여기서 ==연산자의 경우  a==b 의 경우 주소값이 같으므로 true를 반환하지만 a==c or b==c의경우 주소값이 다르므로 false를 반환한다.

equals()메소드라면 어떨까? 

equals()메소드는 비교하는 대상자체 즉 변수의 value값을 통해서 비교한다고 위에 표기해두었다. 이걸 생각하면 a.equlas(b) 는 당연하게 true를 반환한다. 그리고 a.equlas(c)와 a.equlas(b)의 경우도 둘다 value값은 bbb로 동일하기때문에 true를 반환하게 된다.

 

결론

 

==연산자는 Call By Reference (대상을 선언했을 때 ,주소값 부여) 에 따라서 해당 객체나 변수의 주소값을 통한 비교

equals()메소드는 Call By Value(기본적으로 대상에 주소값을 가지지 않는 것으로 값을 할당 받는 형태)에 따라 해당 변수에  value값 자체를 비교하며 boolean값을 반환한다.

 

 

   

1. GIT과 SVN 

1-1.SVN

  1. 소스코드의 효율적인 관리를 위한 형상 관리 도구
  2. 중앙 집중식 소스 관리 (개념적으로 사용하기 쉬움
  3. SVN은 보통 대부분의기능을 완성해놓고 소스를 중앙 저장소에 COMMIT한다
  4. 개발자가 자신만의 version history를 가질 수 없다. (local history를 사용하지만 일시적, 내가 몇일전 까지 했던 작업 내역을 확인 가능하지만 버전관리가 되지 않는다.)
  5. 프로젝트 소스는 SVN 서버의 Trunk라는 곳에 위치 -> 자신의 Local Trunk의 소스를 다운 받아(update) 수정 및 추가 후 다시 업로드(commit)하는 방식자신만의 소스를 다른 개발자들과 떨어져서 작업하려면 Branch(원 소스의 나뭇가지)를 만들어 작업 후 자기자신만 접근하여 개발하며 완성되면 Merge 기능을 사용하여 Trunk와 소스를 합치면 된다
  6.  SVN최대 장점은 직관적이다.  하지만 두 사람이 하나의 파일을 동시에 수정하고 커밋하였을 때 충돌이 일어날 확률이 높아진다.

1-2.GIT

  1.    -소스코드의 효율적인 관리를 위한 형상 관리 도구
  2.    -매우 빠른 속도의 분산형 저장소. SVN보다 많은 기능을 지원하는 대신  익숙해지는데 더많은 시간이 필요함.
  3.    -여러명이 동시에 작업하는 병렬 개발이 가능함
  4.    -소스를 최신으로 유지하면서 개발자들이 원하는 때에 원하는 만큼 수정이 가능

git은 개발자가 자신만의 commit history를 가질 수 있고, 개발자와 서버의 저장소는 독립적으로 관리가 가능하다.

commit한 내용에 실수가 있더라고 바로 서버에 영향을 미치지 않는다.

모든 작업이 로컬에서 이루어지고 네트워크 사용은 원격 저장소로 저장할 때 한번이므로 개발시 처리속도가 빠르다.

원격저장소의 내용이 로컬 저장소에 저장되어 있으므로 중앙 저장소에 에러가 생기면 모든 작업이 마비되는 SVN과는 다르게 원격저장소에 에러가 생겨도 로컬에서 복구하기 용이하고, 히스토리 관리가 잘 제공되어 있어 히스토리 관리가 용이하다.

로컬pc에서 작업내용으로 Commit하여 로컬 저장소에서 반영후 -> 원격저장소에서 fetch로 로컬저장소로 마스터 파일을 받아온후 -> 충돌이 나지않게 merge를 이용하여 합친다음 -> 나의 로컬 저장소 내용을 Push 하여 원격 저장소에 올려 다른 사람들에게 나의 작업내용을 공유한다.

 

소스코드의 유연하게 관리가 가능하다. 

 

2. Git의 Merge와 Rebase의 차이

 

Merge 장점

  • 이해하기쉽다, 원래 브랜치의 컨텍스트를 유치한다. Fast-Forward Merge를 하지 않는다면 브랜치 별로 커밋을 분리해 유지한다. 이러한 기능은 브랜치에 유용하다.
  • 원래 브랜치의 커밋들은 변경되지 않고 계속 유지되어 다른 개발자들의 작업과 공유되는 것에 대해 신경쓸 필요가없다.

Merge 단점 

  • 단순히 모든 사람들이 같은 브랜치에서 작업하기 때문에 merge해야할 때는 merge가 커밋 히스토리상으로 전혀 유용하지 않고 어지럽기만 하다.

 

Rebase 장점

  • 단순한 히스토리
  • 여러 개발자들이 같은 브랜치를 공유할 때 커밋을 합치는 가장 직관적이고 깔끔한 방법.

 

Rease 단점

  • 충돌 상황에서 다소복잡. 커밋 순서대로 Rebase를 하는데, 각 커밋마다 충돌해소를 순서대로 해주어야 한다. 
  • 해당 커밋들을 다른 곳에 푸시한 적이 있다면 히스토리를 다시 쓰는것에 부작용이 발생한다.
  • Git에서는 Push할 수 있으나 당신이 혼자 쓰는 리모트 브랜치 에서만 가능하다.

 

결론

 

1.여러 개발자들이 같은 브랜치를 공유 할 때는 Pull&Rebase가 히스토리를 깔끔하게 유지하는데 좋음.

2. 완료된 기능 브랜치를 다시 합칠 때는 Merge를 사용.

 

  • Remote 와 Local 에 동시에 존재하는 브랜치를 Pull 할 때에는 Rebase 를 사용하도록 한다.
  • 기능 브랜치에 대해서는 Merge 를 사용, Rebase 와 비슷한 동작을 하게되는 Fast-Forward Merge 를 사용하지 않는다.
  • 기능 브랜치에 그 부모 브랜치의 내용을 합칠 때는 로컬 브랜치일 때만 Rebase 로 합침.

 

 

 

pom.xml 추가 D.I

<!-- spring boot jpa -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- h2 -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>

	<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		
		 <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

Member Vo 객체

 

package com.example.test;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="testdb") //디비이름써줌
public class MemberDB {
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY) // 이 Annotation을 붙여주면 해당 변수를  PrimaryKey로 인식한다.
	private Long id;
	private String name;
	private String zipcode;
	private String email;
	private String active;
	


	public MemberDB(Long id, String name, String zipcode, String email, String active) {
		super();
		this.id = id;
		this.name = name;
		this.zipcode = zipcode;
		this.email = email;
		this.active = active;
	}

	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getZipcode() {
		return zipcode;
	}
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getActive() {
		return active;
	}
	public void setActive(String active) {
		this.active = active;
	}
	@Override
	public String toString() {
		return "MemberDB [id=" + id + ", name=" + name + ", zipcode=" + zipcode + ", email=" + email + ", active="
				+ active + "]";
	}
	
	

}

 

jdbc템플릿을 이용하기 위해 member VO의 생성자 유무가 중요하다.

CrudRepository I.O를 상속받아 사용하면 생성자는 protect 생성자이름(){};

만 지정해줘도 자동으로 객체를 할당해준다.

 

위의 @Id,@Entitiy,@table 등의 어노테이션은 이프로젝트는 JPA를 사용하지 않았기에 빼도 아무상관이없다.

package com.example.test;

import java.util.List;

import org.springframework.stereotype.Repository;

@Repository
public interface MemberRepository{

	List<MemberDB> findAll();
	
	int save(MemberDB member);
	
	int update(MemberDB member);
	
	int DeleteById(Long id);
	
	List<MemberDB> findById(Long id);
	
}

 레포지터리 인터페이스 

package com.example.test.JDBC;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.example.test.MemberDB;
import com.example.test.MemberRepository;

@Repository
public class JDBCMemberRepository implements MemberRepository {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	

	
	@Override
	public List<MemberDB> findAll() {
		// TODO Auto-generated method stub
		return jdbcTemplate.query("select * from testdb where active ='TRUE' order by id",(rs,rowNum) -> new MemberDB(
				
				rs.getLong("id"),
				rs.getString("name"),
				rs.getString("zipcode"),
				rs.getString("email"),
				rs.getString("active")
				));
	}

	@Override
	public int save(MemberDB member) {
	
		return jdbcTemplate.update("insert into testdb values(?,?,?,?,default)",
				member.getId(),member.getName(),member.getZipcode(),member.getEmail());
	}

	@Override
	public int update(MemberDB member) {
		// TODO Auto-generated method stub
		return jdbcTemplate.update("update testdb set name = ? where id= ? ",
				member.getName(),member.getId()
				);
	}

	@Override
	public int DeleteById(Long id) {
		// TODO Auto-generated method stub
		return jdbcTemplate.update("update testdb set active = 'FALSE' where id = ?",
				id
				);
	}

	@Override
	public List<MemberDB> findById(Long id,String name) {

		return jdbcTemplate.query("select * from testdb where id =? or name like ?", new Object[] {id,"%"+name+"%"},(rs,rowNum) ->
		
		new MemberDB(	
				rs.getLong("id"),
				rs.getString("name"),
				rs.getString("zipcode"),
				rs.getString("email"),
				rs.getString("active")
				));
	}
	
	

}

JDBC레포지터리 코드

 

스프링 부트서 레포지터리를사용시 반드시 @Repository를 어노테이션해줘야하는걸 잊지말자.

안하면 구동시 오류 생김

 

 

package com.example.test;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping(value ="/members")
@RestController
public class MemberRestAPIController   {
	  @Autowired
	    DataSource dataSource;

	//private MemberRepository memberRepository;

	@Autowired
	private JdbcTemplate jdbcTemplate;
		@PostConstruct 
	    public void run() throws SQLException  {
	        try(Connection connection = dataSource.getConnection()){
	            System.out.println(connection);
	            String URL = connection.getMetaData().getURL();
	            System.out.println(URL);
	            String User = connection.getMetaData().getUserName();
	            System.out.println(User);

	            Statement statement = connection.createStatement();
	            String sql = "CREATE TABLE TESTDB(" +
	                    "ID INTEGER NOT NULL," +
	                    "NAME VARCHAR(255)," +
	                    "ZIPCODE VARCHAR(100),"+
	                    "EMAIL VARCHAR(255),"+
	                    "ACTIVE VARCHAR(10) DEFAULT 'TRUE',"+
	                    "PRIMARY KEY (ID))";
	            //ID INTEGER DEFAULT nextval('seq_id') NOT NULL;
	            //statement.executeUpdate(sql);
	        }

	     // jdbcTemplate.execute("INSERT INTO TESTDB VALUES(10002, '정성훈2','143602','fixblack@gmail.com',default)");
		

	    }
	
	@Autowired
	private MemberRepository memberRepository;

	
	//전체 목록
	@GetMapping
	public List<MemberDB> listAllmemeber(){
		
	    List<MemberDB> allMembers = memberRepository.findAll();
		System.out.println(allMembers);
		return allMembers;
		
	}
	
	//삽입

	@PostMapping
	public ResponseEntity<List<MemberDB>> memberadd(@RequestBody MemberDB member) {
		
		memberRepository.save(member);
		return memberSearch(member.getId());
	}
	
	//수정 @Put
	
	@PutMapping
	public String memberupdate(@RequestBody MemberDB member){//id로
		
		memberRepository.update(member);
		return "redirect:/members";
	}
	
	@DeleteMapping("/{id}")
	public String memberDelete(@PathVariable Long id){
		
		memberRepository.DeleteById(id);
		return "redirect:/members";
	}
	
	//특정 아이디 조회 id or 이름
	
	//조회
	
	@GetMapping("/{id}")
	public ResponseEntity<List<MemberDB>> memberSearch(@PathVariable Long id) { //@PathVariable
		
		 List<MemberDB> searchMember = memberRepository.findById(id);
		System.out.println(searchMember);
		return new ResponseEntity<List<MemberDB>>(searchMember,HttpStatus.OK);
		
	}
	
}
	

    

 

 

위의 주석은 초기에 CrudRepository를 활용해서 코드를 작성하려했지만 FindById쪽이 잘 구현되지않아

JDBC를 사용하는것으로 방향을 선회했다. 하는법은 나중에 코드를 더분석하고 해결해 봐야할듯 하다.

 

 

[Spring] ResponseEntity는 왜 쓰는 것이며 어떻게 쓰는걸까?

ResponseEntity, @ResponseBody Client 의 플랫폼에 구애받지 않는 독립적인 RestFul API를 개발하기 위해, 상태코드, HttpHeader, 응답메시지, 반환 데이터를 모두 지정해서 반환해주기 위해 사용하는 것이다. Cl..

a1010100z.tistory.com

RestFulAPI를 구현하려면 ResPonseEntity사용을 권한다. 그이유는 위의 링크서 확인이 가능하다.

 

spring.datasource.hikari.maximum-pool-sie=4
spring.datasource.url=jdbc:postgresql://192.168.11.222:5432/jshdb
spring.datasource.username=jsh
spring.datasource.password=1234

application.roperties의 코드이다.

여기서 주의해야할점은 url주소 지정인데

 

postgresql과 연동하기위해 docker초기화면서 보여지는 ip주소와 뒤에 5432는 컨테이너를 생성할때 할당하는 포트번호이다 

뒤는 연동할 DB이름을 적어주면된다.

 

postman프로그램을 사용하여 JSON형태로 값을 send하여 확인하는 화면

 

RESTful API를 사용하면 어느 클라이언트,운영체에 상관없이 동일한 시스템을 구성 할 수 가있다.

그 만큼 유지보수 및 수정이 훨씬 수월해지고 익숙해지면 개발자에게 참좋은 방식이라 생각된다.

 

 

추가

   public void run(ApplicationArguments args) throws Exception {
	        try(Connection connection = dataSource.getConnection()){
	            System.out.println(connection);
	            String URL = connection.getMetaData().getURL();
	            System.out.println(URL);
	            String User = connection.getMetaData().getUserName();
	            System.out.println(User);

	            Statement statement = connection.createStatement();
	            String sql = "CREATE TABLE TESTDB1(" +
	                    "ID INTEGER NOT NULL," +
	                    "NAME VARCHAR(255)," +
	                    "ZIPCODE VARCHAR(100),"+
	                    "EMAIL VARCHAR(255),"+
	                    "ACTIVE VARCHAR(10) DEFAULT 'TRUE',"+
	                    "PRIMARY KEY (ID))";
	            //ID INTEGER DEFAULT nextval('seq_id') NOT NULL;
	            statement.executeUpdate(sql);
	        }

스프링 부트를 통해서 직접 테이블을 생성하고 싶을때 쓰는 구문이다.

클래스에 implements ApplicationRunner를 붙여주고 run함수는 오버라이드 해주면 정상적으로 작동한다.

 

+ Recent posts