오랜 외도 (파견 근무) 끝에 본사 복귀 후 내부 서비스 운영 팀장을 맡게 되었는데요. 

업무 파악 시작한지 한주도 되기전에 충격에 빠지고 말았습니다. 

서비스 중인 화면 이동에 너무 오랜 시간이 소요 되는것을 보고 로그를 찍어 봤는데...

미친듯이 찍혀 나오는 DB 조회 로그들... 심지어 메뉴 이동시 마다 메뉴 목록 + 메뉴별 role 정보 조회를 하고 있는... ㅠㅠ

 

운영중인 서비스는 숨넘어 가기 직전의 응급 환자 상태 였으며, JPA 를 이용하면서 Entity 구조를 잘못 잡아 N+1 이슈 발생한 케이스 였다는걸 알아 내는데 그리 오랜 시간이 걸리진 않았습니다. 

 

Spring boot 의 JPA 는 무엇이며 N+1 이슈는 어떤건지, 그리고 해결 방법에 대해 간단히 정리 하겠습니다. 

 

 

JPA 란? 

JPA(Java Persistence API)는 자바 애플리케이션과 관계형 데이터베이스를 연결하는 기술입니다. JPA는 ORM(Object-Relational Mapping)을 기반으로 하며, 객체 지향 프로그래밍과 관계형 데이터베이스 간의 매핑을 단순화하고 개발자가 데이터베이스에 대한 저수준의 작업을 추상화합니다.

JPA를 사용하면 객체와 테이블 간의 매핑을 어노테이션 또는 XML 설정으로 정의할 수 있습니다. 이를 통해 개발자는 SQL 쿼리를 직접 작성하지 않고도 객체 지향적인 방식으로 데이터베이스에 접근할 수 있습니다. JPA는 엔티티(Entity), 영속성 컨텍스트(Persistence Context), 엔티티 매니저(Entity Manager) 등 다양한 개념과 기능을 제공합니다.

그러나 JPA를 사용할 때 발생할 수 있는 성능 문제 중 하나가 "N+1 이슈"입니다.

 

N+1 이슈란?

한 번의 쿼리로 가져온 엔티티들과 관련된 연관 엔티티들을 조회할 때 추가적인 N번의 쿼리가 발생하는 현상을 의미합니다. 예를 들어, 게시물 목록을 조회하는 쿼리에서 각 게시물의 작성자 정보를 함께 가져와야 할 경우, 게시물 개수만큼의 추가 쿼리가 실행되어 성능 저하를 초래합니다.

 

N+1 이슈는 다음과 같은 상황에서 주로 발생합니다.

일대다(One-to-Many) 또는 다대다(Many-to-Many)와 같은 연관 관계에서 Lazy Loading 설정이 되어 있을 때.

연관 엔티티에 대한 필요한 정보가 사용되기 전까지 초기화되지 않았을 때.

 

해결 방법으로는 다음과 같은 접근 방식들이 있습니다:

  • Fetch Join 사용: Fetch Join은 JPQL(Java Persistence Query Language) 또는 Criteria API를 사용하여 한 번의 쿼리로 모든 필요한 데이터를 한 번에 가져옵니다. 이렇게 하면 N+1 문제가 발생하지 않습니다.
  • Batch Size 설정: Hibernate에서 제공하는 @BatchSize 어노테이션을 사용하여 일대다 또는 다대다 관계에서 한 번에 가져올 엔티티의 수를 지정할 수 있습니다.
  • Entity Graphs 활용: JPA 2.1부터 도입된 Entity Graphs 기능을 사용하여 필요한 연관 엔티티들도 함께 로딩하도록 명시적으로 지정할 수 있습니다.
  • DTO(Data Transfer Object) 활용: 필요한 데이터만 선택하여 DTO 객체로 변환하여 반환함으로써 원하는 정보만 조회하고 N+1 문제를 회피할 수 있습니다.

N+1 이슈는 JPA 애플리케이션 개발 시 주의해야 할 성능 문제 중 하나입니다. 위에서 소개한 해결 방법 중 상황에 맞게 가장 적합한 방법을 선택하여 성능 향상을 추구할 수 있습니다 

 

 

JPA N+1 이슈에 대한 예제 코드와 해결 방법 예제 (여기서는 Fetch join 만)

예를 들어, 게시물(Post)과 작성자(Author)라는 두 개의 엔티티가 일대다 관계로 연관되어 있다고 가정해보겠습니다. 각 게시물에 대한 작성자 정보를 조회할 때 N+1 이슈가 발생할 수 있습니다.

 

엔티티 클래스 정의:

@Entity
public class Post {
    @Id
    private Long id;
    private String title;
    
    @ManyToOne(fetch = FetchType.LAZY)
    private Author author;
    // Getters and Setters
}

@Entity
public class Author {
    @Id
    private Long id;
    private String name;
    // Getters and Setters
}

위의 예제에서는 Post 엔티티가 Author 엔티티와 Many-to-One 관계로 매핑되어 있습니다.

FetchType.LAZY 옵션을 사용하여 게시물을 조회할 때 작성자 정보는 지연 로딩됩니다.

 

 

N+1 이슈 발생하는 코드:

List<Post> posts = entityManager.createQuery("SELECT p FROM Post p", Post.class).getResultList();

for (Post post : posts) {
    System.out.println("Title: " + post.getTitle());
    System.out.println("Author: " + post.getAuthor().getName()); // N+1 이슈 발생!
}

위의 코드에서는 모든 게시물을 조회한 후 각 게시물의 작성자 정보를 출력하고 있습니다.

하지만 post.getAuthor().getName() 호출 시마다 추가적인 쿼리가 실행되므로 N+1 문제가 발생합니다.

 

 

N+1 이슈 해결 방법 - Fetch Join 사용:

List<Post> posts = entityManager.createQuery("SELECT p FROM Post p JOIN FETCH p.author", Post.class)
        .getResultList();

for (Post post : posts) {
   System.out.println("Title: " + post.getTitle());
   System.out.println("Author: " + post.getAuthor().getName()); // 추가 쿼리 없이 작동!
}

위의 코드에서는 Fetch Join을 사용하여 한 번의 쿼리로 모든 필요한 데이터를 가져오도록 변경되었습니다.

"SELECT p FROM Post p JOIN FETCH p.author" 쿼리는 게시물과 작성자를 함께 로딩하므로 N+1 문제가 발생하지 않습니다.

 

이처럼 Fetch Join은 JPQL 또는 Criteria API에서 사용할 수 있는 방법 중 하나입니다.

다른 방법으로도 Batch Size 설정, Entity Graphs 활용 등이 있으며, 상황에 따라 가장 적합한 해결 방법을 선택하여 성능 향상을 할 수 있습니다.

 

개인적으로 선호하는 mapper 방식을 활용하는 방법에 대해서는 다음에 기회가 되면 추가로 작성 하겠습니다. 

 

 

실질적으로 저는 queryDsl 방식과 mybatis mapper 방식을 병행하는 것을 선호합니다. 

복잡도 높은 쿼리문 작성이나 튜닝이 필요한 경우 mapper 방식이 훨씬 편하다고 느껴집니다.

QueryDsl 의 경우 entity 구조만 명확하게 잘 잡아 둔다면 간단한 쿼리문의 경우 편하게 사용할 수 있으며, DML 을 치는 경우는 N+1 이슈에서 자유롭기 때문에 활용도가 높습니다. 

 

서비스 상에 Excel 파일 다운로드 기능이 있고, 다운 받을때 N+1 이슈가 있는 경우 proxy server error 로 서버가 사망하는 환상적인? 경험을 하실 수 있습니다. 

블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,

안녕하세요. 제임스입니다. 

 

최근에 지속적으로 안드로이드 레이아웃에 대한 소개를 하고 있는데요. 

이번에는 GridLayout 에 대한 내용 정리 하겠습니다. 

 

■ GridLayout 이란?

 

안드로이드의 GridLayout 은 2차원 격자 무늬 형태의 레이아웃으로 수직, 수평의 라인으로 구성되어 행과 열의 집합 형태로 만들어 지는 레이아웃입니다. 

그리드 라인은 인덱스 (index) 로 참조 되며 좌상단에서 부터 0, 0 좌료값으로 시작하게 됩니다. 

 

안드로이드 API Level 14 에 추가된 레이아웃으로 LinearLayout 과 RelativeLayout 의 단점을 보완하기 위해 만들어 메모리 효율이 좋다고 알려 지긴 했는데요, 사실 격자형태의 레이아웃을 구성해야 하는 경우가 아니라면 쓸일이 없고, 단말기 성능이 좋아 지면서 레이아웃에 따른 메모리 효율성을 따지기는 어렵게 되었습니다. 

하지만 여전히 격자 형태의 레이아웃을 구성하는 앱을 개발해야 한다면 정말 매력적인 레이아웃임은 두말할 필요가 없습니다. 

 

java.lang.Object

↳ android.view.View

↳ android.view.ViewGroup

↳ android.widget.GridLayout

 

■ GridLayout 속성

GridLayout 속성에 대해 알아 보겠습니다. 

 

◎ 부모뷰에서 주로 사용하는 속성

columnCount : 부모뷰가 가지고 있는 행의 수

rowCount : 부모뷰가 가지고 있는 열의 수

 

◎ 자식뷰에서 주로 사용하는 속성

layout_column : 자식뷰의 행 좌표 (layout_row 속성과 세트로 사용)

layout_row : 자식뷰의 열 좌표 (layout_column 속성과 세트로 사용)

layout_columnSpan : 행으로 차지하는 자리수 

layout_rowSpan : 열로 차지하는 자리수

layout_gravity : 자식뷰의 위치를 설정 하는 속성으로 셀의 중앙 / 좌 / 우 / 상단 / 하단 등의 속성 값을 지정

 

 

■ GridLayout 사용예

 

간단한 예제와 함께 사용 방법에 대해 알아 보겠습니다. 

 

 

첫번째 라인을 보면 숫자가 3 > 1 > 2 순으로 나열 되어 있습니다. 

코드는 아래와 같이 작성 했습니다. 

 

<Button
    android:text="1" />

<Button
    android:text="2" />

<Button
    android:layout_column="0"
    android:layout_row="0"
    android:text="3" />

세번째 버튼에 layout_column layout_row 속성을 각각 0 으로 정의 했습니다. 

이는 임의로 개발자가 원하는 자식뷰를 특정 위치에 셋팅 하는 방식입니다. 

즉, 좌표값 0, 0 위치에 세번째 버튼을 배치함으로 인하여 자연스럽게 버튼 1, 2 번이 뒤로 밀려 나오게 됩니다. 

 

 

두번째 라인은 4, 5번 버튼 두개 밖에 없으며 5번 버튼이 두자리를 차지하고 있습니다. 

<Button
    android:layout_column="0"
    android:layout_row="2"
    android:text="4" />

<Button
    android:layout_column="1"
    android:layout_row="2"
    android:layout_columnSpan="2"
    android:layout_gravity="fill_horizontal"
    android:text="5" />

4번 버튼에도 layout_columnlayout_row 값을 0, 2 로 지정하여 첫번째 행의 두번째 열에 위치하게 했습니다. 

5번 버튼에도 layout_columnlayout_row 값을 1, 2 로 지정하여 두번째 행의 두번째 열에 위치하게 했습니다. 

그리고 5번 버튼에 columnSpan 속성을 2로 지정하여 열을 두자리 만큼 차지 하라고 지정했습니다. 

HTML 을 사용해보신 분들을 익숙한 단어가 보이실겁니다. 다만 HTML 과 다른건 layout_gravityfill 또는 fill_horizontal 로 지정을 해주지 않으며 원하는 만큼 자리를 차지 하지 않습니다. 

 

여기서 뭔가 이상한점이 보이지 않으신가요? 

layout_row 값이 2로 설정 되었는데 화면상에서는 2행에 있습니다. 

즉, layout_row 가 1인 자식뷰는 없는 레이아웃 구조 입니다. 

 

만약 위 코드에서 4번 버튼의 layout_row 값을 1로 설정하면 어떻게 될까요? 

<Button
    android:layout_column="0"
    android:layout_row="1"
    android:text="4" />

<Button
    android:layout_column="1"
    android:layout_row="2"
    android:layout_columnSpan="2"
    android:layout_gravity="fill_horizontal"
    android:text="5" />

 

 

위와 같이 2행에는 4번 버튼만 존재하고 3행에 5번 버튼만 존재하게 됩니다. 

 

 

세번째 및 네번째 라인 은 6번 버튼이 첫번재 열을 두자리나 차지하고 있습니다. 

<Button
    android:layout_gravity="fill_vertical"
    android:layout_rowSpan="2"
    android:text="6"
    />
<Button
    android:text="7" />
<Button
    android:text="8" />
<Button
    android:text="9" />
<Button
    android:text="10" />

6번 버튼에 layout_rowSpan 을 2로 줬습니다. 열을 두자리 차지하라는 의미 인데요. 

위 5번 버튼과 동일하게 layout_gravity 속성을 지정해줘야 합니다. 여기서는 수직방향으로 두자리를 차지 하므로 fill 또는 fill_vertical 값을 꼭 지정해주셔야 합니다. 

 

 

다섯번째 및 여섯번째 라인은 12번 버튼이 2 x 2 만큼 자리를 차지하고 있습니다. 

<Button
android:text="11" />

<Button
android:layout_gravity="fill_horizontal|fill_vertical"
android:layout_columnSpan="2"
android:layout_rowSpan="2"
android:text="12" />

<Button
android:text="13" />

12번 버튼의 layout_columnSpanlayout_rowSpan 값을 각각 2 씩 줬습니다. 

행과 열을 2자리씩 차지하라는 의미 이며 수직 및 수평 방향으로 2자리씩 차지해야 하므로 fill_horizontalfill_vertical 를 같이 사용해야 합니다. 그래서 파이프라인 "|" 을 이용하여 위와 같이 사용 하실 수 있으며 그냥 fill 하나만 사용해도 동일한 효과를 적용할 수 있습니다. 

 

 

xml 파일 전체 코드는 아래와 같습니다. 

<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:columnCount="3"
    android:rowCount="6"
    android:orientation="horizontal"
    android:background="#b6e686"
    android:layout_margin="10dp"
    >

    <Space />

    <!-- 1열 -->
    <Button
        android:text="1" />

    <Button
        android:text="2" />

    <Button
        android:layout_column="0"
        android:layout_row="0"
        android:text="3" />

    <!-- 2열 -->
    <Button
        android:layout_column="0"
        android:layout_row="2"
        android:text="4" />

    <Button
        android:layout_column="1"
        android:layout_row="2"
        android:layout_columnSpan="2"
        android:layout_gravity="fill_horizontal"
        android:text="5" />

    <!-- 3열 & 4열 -->
    <Button
        android:layout_gravity="fill"
        android:layout_rowSpan="2"
        android:text="6"
        />
    <Button
        android:text="7" />
    <Button
        android:text="8" />
    <Button
        android:text="9" />
    <Button
        android:text="10" />

    <!-- 5열 & 6열 -->
    <Button
        android:text="11" />

    <Button
        android:layout_gravity="fill_horizontal|fill_vertical"
        android:layout_columnSpan="2"
        android:layout_rowSpan="2"
        android:text="12" />

    <Button
        android:text="13" />

</GridLayout>

 

GridLayout 속성 값 중에 columnCount 및 rowCount 속성이 있습니다. 

각각 3 과 6으로 지정하여 3x6의 격자형 레이아웃을 생성 했습니다. 

 

 

위에 언급한 속성들 이외에도 

layout_margin, layout_padding, layout_columnWeight, layout_rowWeight, layout_background 등등 일반적인 자식뷰에서 사용할 수 있는 속성들은 거의 모두 사용할 수 있습니다. 

참고 하시면 좋을 것 같습니다. 

 

 

 도움이 되셨다면 로그인이 필요 없는 

▼ 하트 클릭 한번 부탁 드립니다 

감사합니다 :D



블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,

 

 

안녕하세요. 제임스 입니다. 

 

자바에서 숫자에 콤마를 찍어 금액을 표기 하는 방법에 대해 알아 보겠습니다. 

 

 

■ DecimalFormat 을 이용하여 숫자에 콤마 찍기

 

 

DecimalFormat 은 NumberFormat 을 상속받고 있습니다. 

 

DecimalFormat(String pattern) 컨스트럭터를 이용하여 표현하고자 하는 패턴을 입력합니다. 

 

패턴 관련 정보는 아래 링크 참조 하시면 됩니다. 

https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html#numberpattern

 

 

1
DecimalFormat formatter = new DecimalFormat("###,###");
cs

 

위와 같이 패턴을 ###,### 와 같은 형식으로 입력 했습니다. 

이는 앞에 세자리 숫자 + " , " + 세자리 숫자 형태의 패턴을 의미 합니다. 

 

즉, 6자리가 넘어 가더라도 뒤 세자리 숫자 앞에 콤마 ( , ) 를 붙여 주게 되므로 백만 이상값을 표기 하는데 아무런 문제가 없습니다. 

 

사용 방법은 아래와 같습니다. 

 

1
formatter.format(12345);
cs

 

DecimalFormat 클래스의 format(long number) 함수를 이용하여 원하는 패턴의 결과 값을 가져올 수 있습니다. 

 

 

예제를 보시겠습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
DecimalFormat formatter = new DecimalFormat("###,###");
        
int price1 = 123;
int price2 = 1234;
int price3 = 123456;
int price4 = 1234567;
        
System.out.println("price1 금액 표기 결과 ["+price1+"] ==> "+formatter.format(price1));
System.out.println("price2 금액 표기 결과 ["+price2+"] ==> "+formatter.format(price2));
System.out.println("price3 금액 표기 결과 ["+price3+"] ==> "+formatter.format(price3));
System.out.println("price4 금액 표기 결과 ["+price4+"] ==> "+formatter.format(price4));
cs

 

실행 결과는 아래와 같습니다. 

 

Results

price1 금액 표기 결과 [123] ==> 123

price2 금액 표기 결과 [1234] ==> 1,234

price3 금액 표기 결과 [123456] ==> 123,456

price4 금액 표기 결과 [1234567] ==> 1,234,567

 

 

▶ 숫자에 콤마 표기 및 소수점 표기 하기

 

소숫점 까지 표기 하는 방법은 의외로 쉽습니다. 

 

1
DecimalFormat formatter = new DecimalFormat("###,###.##");
cs

 

패턴을 ###,###.## 

위와 같이 기존패턴에 .## 을 추가 하여 소수점 두자리 까지 표현 하는 것으로 정의 했습니다. 

이때 소수점 두번째 자리 아래는 반올림처리 됩니다. 

 

1
2
3
4
5
6
7
8
9
DecimalFormat formatter = new DecimalFormat("###,###.##");
        
int price1 = 1234567;
double price2 = 1234567.123;
double price3 = 1234567.127;
        
System.out.println("price1 금액 표기 결과 ["+price1+"] ==> "+formatter.format(price1));
System.out.println("price2 금액 표기 결과 ["+price2+"] ==> "+formatter.format(price2));
System.out.println("price3 금액 표기 결과 ["+price3+"] ==> "+formatter.format(price3));
cs

 

실행 결과는 아래와 같습니다. 

 

Results

price1 금액 표기 결과 [1234567] ==> 1,234,567

price2 금액 표기 결과 [1234567.123] ==> 1,234,567.12

price3 금액 표기 결과 [1234567.127] ==> 1,234,567.13

 

price2 와 price3 의 소수점 세번째 자리값을 비교 해보시면 반올림 처리 됨을 알 수 있습니다. 

 

 

 도움이 되셨다면 로그인이 필요 없는 

▼ 하트 클릭 한번 부탁 드립니다 

감사합니다 :D

 

 

블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,

 

 

 ■ Java 배열 정렬 (내림차순 vs 올림차순)

 

 

Arrays.sort() 함수를 이용하여 올림차순 및 내림차순 정렬을 할 수 있습니다. 

 

 

Syntax

 

public static void sort ( primitive_type_array a )

- 인자 값으로 primitive data type 인 byte[], char[], double[], long[], int[], float[] 등을 이용 합니다.

 

public static void sort ( primitive_type_array a, int fromIndex, int toIndex )

- 인자 값으로 primitive data type 인 byte[], char[], double[], long[], int[], float[] 등을 이용 하며, 정렬 시작 index 값 및 종료 index 값을 지정 합니다. 

 

public static void sort ( Object[] a )

- 인자 값으로 Object (객체) 를 받습니다. Integer[], Double[], Character[] 등의 값을 받을 수 있습니다. 

 

public static void sort ( Object[] a, int fromIndex, int toIndex )

- 인자 값으로 Object (객체) 를 받습니다. Integer[], Double[], Character[] 등의 값을 받을 수 있으며, 정렬 시작 index 값 및 종료 index 값을 지정 할 수 있습니다. 

 

public static <T> void sort ( T[] a, Comparator<? super T> c )

- 인자 값으로 객체를 받으며, 지정된 Comparator 가 가리키는 순서에 따라 지정된 객체의 배열을 정렬합니다.

 

public static <T> void sort ( T[] a, int fromIndex, int toIndex, Comparator<? super T> c )

- 인자 값으로 객체를 받으며, 지정된 Comparator 가 가리키는 순서에 따라 지정된 객체의 배열을 정렬하며, 정렬 시작 index 값 및 종료 index 값을 지정 합니다.

 

 

 

Example

 
▶ 올림차순

1
2
3
4
5
int[] arr = {214193116};
Arrays.sort(arr);
for(int i = 0; i < arr.length; i++){
    System.out.println(arr[i]);
}
cs

 

primitive data type 배열을 Arrays.sort() 함수에 입력하면 배열의 값이 변경 됩니다. 

올림 차순으로 소트를 했으므로 아래와 같이 배열이 변경 됩니다. 

 

arr =

 

위 코드를 실행 시키면 아래와 같은 결과 값이 나옵니다. 

 

4

16

19

21

31

 

 

1
2
3
4
5
int[] arr1 = {214193116};
Arrays.sort(arr1, 1, arr1.length);
for(int i = 0; i < arr1.length; i++){
    System.out.println(arr1[i]);
}
cs

 

첫번째 예제와 동일한 값을 가진 배열을 준비했습니다. 

sort() 함수의 인자 값이 세개로 첫번째는 배열을 두번째와 세번째는 변경할 index 범위를 지정합니다. 

 

위 예제에서는 변경할 index 값을 1 ~ 배열의 길이 만큼 지정 했습니다. (1 ~ 5) 

즉, 첫번째 21 값을 건드리지 않고 index 값이 1인 두번째 값 부터 마지막 값 까지만 정렬을 시킵니다.

변경 시 아래와 같은 순서로 배열이 정렬 됩니다. 

 

arr =

 

위 코드를 실행 하면 아래와 같은 결과를 얻을 수 있습니다. 

 

21

4

16

19

31

 

 

▶ 내림차순

 

1
2
3
4
5
Integer[] arr2 = {42153};
Arrays.sort(arr2, Collections.reverseOrder());
for(int i = 0; i < arr2.length; i++){
    System.out.println(arr2[i]);
}
cs

 

앞선 두개의 예제와 다르게 primitive data type 이 아니라 객체의 배열을 이용했습니다. 

Comparator 로는 Collections class 의 reverseOrder() 함수를 이용 했습니다. 

지금까지와 반대 오더 즉, 반대로 소트 하겠다는 의미로 내림차순 적용을 합니다. 

 

arr2 =

 

위와 같이 배열 정렬이 됩니다.

코드를 실행 하면 아래와 같습니다.

 

5

4

3

2

1

 

 

배열의 올림차순 및 내림차순 정렬에 대해 알아 봤습니다. 

 

 

 

 도움이 되셨다면 로그인이 필요 없는 

▼ 하트 클릭 한번 부탁 드립니다 

감사합니다 :D



 

블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,

 

 

안녕하세요. 제임스 입니다.

 

이번에는 개발 중 종종 발생하는 오류중 하나인 NumbreFormatException 에 대해 정리 해보겠습니다. 

 

NumbreFormatException 은 왜 발생 하는 것일 까요? 

단어를 잘 보시면 이유를 알 수 있습니다. 

 

Number 와 관련된 오류 인데... 

Format Exception 이라고 합니다. 즉, 형식 오류라는 의미 인데요. 

풀어서 이야기 하면 숫자 형식 오류 라는 의미가 됩니다. 

 

 

그렇다면 어떤 경우에 발생하는지 예제를 보면서 다시 살펴 보겠습니다.

 

앞서 문자열을 숫자로 변환하는 방법에 대해 정리 했었는데요. (아래 링크 참조)

2018/03/06 - [Java] - [ 자바 코딩 ] Java Integer.parseInt

 

이와 관련하여 잘못된 사용으로 인해 오류가 발생 할 수 있습니다. 

1
2
3
4
5
6
7
8
package com.james.test;
public class JavaNumbers {
    public static void main(String[] args) {
        String str = "O1O";
        System.out.println(Integer.parseInt(str));
    }
}
 
cs

 

위 코드를 보시면 String str = "010"; 이라고 입력 되어 있습니다. 

사실 이 코드는 숫자 010 이 아닌 영문 대문자 O 와 숫자1 의 조합으로 영문 소문자로 사용 시 아래와 같이 표현 할 수 있습니다. 

String str = "o1o";

즉, 숫자 형이 아닌 말 그래로 문자열입니다. 

 

문자열을 숫자형으로 변환한다???

절대 불가능한 일이죠. 

이 경우 위 코드를 실행 시키명 아래와 같은 오류를 볼 수 있습니다. 

 

Exception in thread "main" java.lang.NumberFormatException: For input string: "O1O"

at java.lang.NumberFormatException.forInputString(Unknown Source)

at java.lang.Integer.parseInt(Unknown Source)

at java.lang.Integer.parseInt(Unknown Source)

at com.james.test.JavaNumbers.main(JavaNumbers.java:5)

 
 

이런 오류가 발생 하면 안되 겠지만 발생하는 경우가 있기 때문에 Exception 처리를 해주는 것이 중요 합니다. 

 

그래서 Integer.parseInt() 를 사용할 경우 try ~ catch ~ 를 이용하여 감싸줍니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.james.test;
public class JavaNumbers {
    public static void main(String[] args) {
        try {
            String str = "010";
            System.out.println(Integer.parseInt(str));
        } catch (NumberFormatException e) {
            // NumberFormatException 이 발생한 경우 처리 방법
        } catch (Exception e) {
            // Exception 이 발생한 경우 처리 방법
        }
    }
}
 
cs

 

각각의 Exception 종류에 따라 원하는 코드를 작성하여 처리 하여 주면 됩니다. 

만약 위와 같이 아무런 오류 처리를 하지 않을 경우 오류가 발생하더라도 아무런 반응을 하지 않게 됩니다.

 

위 코드에서는 정상적으로 숫자 010 을 입력 하였습니다. 

문제가 되던 오입력된 숫자형 무자열을 수정 하였으니 제대로 나오겠죠? ^^

 

실행 결과 값은 아래와 같습니다. 

 

10 

 

 

 도움이 되셨다면 로그인이 필요 없는 

▼ 하트 클릭 한번 부탁 드립니다 

감사합니다 :D



블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,

 

 

안녕하세요. 제임스 입니다. 

 

이번에는 Java 에서 String 을 다룰때 유용하게 사용할 수 있는 함수 중 한가지인 split 함수에 대해 알아 보겠습니다. 

 

■ String[] split(String regex)

 

split 함수는 입력받은 정규표현식 또는 특정 문자를 기준으로 문자열을 나누어 배열(Array) 에 저장하여 리턴합니다. 

 

String str = "010-1234-5678";
String[] mobNum = str.split("-");
String ret1 = mobNum[0];
String ret2 = mobNum[1];
String ret3 = mobNum[2];

System.out.println("ret1 = "+ret1);
System.out.println("ret2 = "+ret2);
System.out.println("ret3 = "+ret3);

위와 같은 휴대폰 번호가 있다고 가정하고 이를 split("-") 했을 경우 

"010", "1234", "5678" 로 나누어져 배열에 저장됩니다. 

 

ret1 = 010

ret2 = 1234

ret3 = 5678

 

System.out.println("휴대폰번호 => "+ret1+"-"+ret2+"-"+ret3);

위와 같이 다시 휴대폰 번호 형태로 중간에 "-" 를 추가 해서 조합하면 결과는 아래와 같이 나옵니다. 

 

휴대폰번호 => 010-1234-5678

 

 

다른 예제 하나 더 보겠습니다. 

String str2 = "서울,대전,대구,부산,인천,울산";
String[] cityArr = str2.split(",");

for (int i = 0; i < cityArr.length; i++){
    System.out.println(cityArr[i]);
}

6개 도시명을 쉼표로 구분하여 나열했는데요, 이를 split(",") 했습니다. 

그리고 cityArr 의 length 만큼 for loop 을 돌려 결과 값을 찍어 봤습니다. 

 

서울

대전

대구

부산

인천

울산

 

결과 값이 이렇게 나옵니다. 참 쉽죠? 

 

정규표현식을 이용한 split 방법도 있는데요. 이는 정규표현식에 대한 내용을 포스팅한 이후 다시 한번 정리 하겠습니다. 

 

 

■ String[] split(String regex, int limit)

 

위의 인자값 하나만 받는것과 달리 int 형의 두번째 인자 값을 받는 split 함수 입니다. 

두번째 인자 값은 배열의 크기를 결정합니다. 

예제를 보면서 설명 드리겠습니다. 

 

String str2 = "81-2-010-1234-5678";
String[] arr = str2.split("-", 2);
System.out.println("ret4 = "+arr[0]);
System.out.println("ret5 = "+arr[1]);

위와 같은 String 값이 있다고 했을때 "-" 를 인자 값으로 split 하면서 배열의 크기는 2로 한정 했습니다. 

첫번째 "-" 를 기준으로 split 하면 아래와 같은 결과 값이 나옵니다. 

 

ret4 = 81

ret5 = 2-010-1234-5678

 

arr[] 배열에 이미 ret4 와 ret5 가 들어 있으므로 더이상의 배열을 생성하지 않고 위 값이 최종 결과 값이 됩니다. 

 

 

다른 예를 하나 더 보겠습니다. 

String str2 = "81-2-010-1234-5678";
String[] arr2 = str2.split("-", 4);
System.out.println(arr2.length);
for (int i = 0; i < arr2.length; i++){
    System.out.println("ret"+i+" = "+arr2[i]);
}

동일한 String 값을 두번째 인자값으로 4를 입력 합니다. 

arr2 배열 크기를 4로 지정한겁니다. 

 

어떤 결과 값이 나올지는 예상이 되시죠? ^^

 

ret0 = 81

ret1 = 2

ret2 = 010

ret3 = 1234-5678

 

위와 같이 arr2 배열에는 4개의 값이 들어 가게 됩니다. 

 

 

이상 자바 문자열을 자르기 해봤습니다. 

 

 

 도움이 되셨다면 로그인이 필요 없는 

▼ 하트 클릭 한번 부탁 드립니다 

감사합니다 :D



블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,

 

 

안녕하세요. 제임스 입니다. 

 

Java 사용중 문자열을 원하는 위치에서 잘라야 하는 경우가 있습니다. 

이때 사용하는 하는 java 함수가 바로 substring 입니다. 

이번에는 이 substring 에 대해 자세히 알아 보겠습니다. 

 

 

■ String substring(int index)

 

substring 함수는 두가지가 있으며, 그중 첫번째로 인자값을 하나만 받는 함수 입니다. 

인자값은 int 형으로 substring 하고자 하는 문자열의 앞에서 부터 몇번째 위치인가를 지정하는 값입니다. 

입력받은 인자값을  index 로 해당 위치를 포함하여 이후의 모든 문자열을 리턴 시키는 함수 입니다. 

 

이때 이 index 값은 0 부터 시작 합니다. (첫번째 자리에 있다고 1 부터 시작한다고 생가하면 안됩니다.)

 

String str = "0123456789";

위와 같은 문자열이 있을때 0 ~ 4 까지를 제외한 56789 를 가져오고 싶을 경우 아래와 같이 호출 하면 됩니다. 

str.substring(5)

index 값이 5인 위치 이후 값을 가져 오라고 했으므로 56789 를 리턴하게 됩니다. 

 

 

String str2 = "자바코딩배우기";
System.out.println(str2.substring(4));

위와 같은 문자열을 substring(4) 를 하면 index 가 4 인 위치의 문자를 포함한 문자열을 리턴합니다. 

 

 문자열
index 값  0 1 2 3 4 5

 

위 표를 보시면 "배우기" 를 가져오기 위해서는 index 값을 4 로 입력하면 된다는 것을 알 수 있습니다. 

처음에 언급 했지만 index 는 0 부터 시작합니다 :)

 

 

String str3 = "자바코딩 배워볼까?";
System.out.println(str3.substring(5));

이번 문자열에는 띄어쓰기를 한 것이 보입니다. 물론 이 공백문자도 하나의 문자이므로 한자리를 차지 합니다. 

 

문자열   ? 
index 값 0 1 2 3 4 5 6 7 8 9

 

"배워볼까?" 라는 값을 리턴받기 위해 index 값을 5로 입력했다는 것을 알 수 있습니다. 

 

 

지금까지는 입력 인자값이 한개인 substring 함수를 알아봤습니다. 

이제 입력 인자값이 두개인 substring 에 대해 알아 보겠습니다. 

 

 

■ String substring(int beginIndex, int endIndex)

 

이번에 알아볼 substring 함수는 입력 인자값이 두개 입니다. 

 

첫번째 입력 받는 인자 값은 인자값이 한개인 substring 과 같이 가져올 문자열의 시작 부분을 지정합니다. 

두번째 입력 받는 인자 값은 가져올 문자열의 끝 부분을 지정 하는 것으로 substring(in index) 가 시작부분만 지정하고 나머지 모든 문자열을 리턴하는것과 차이가 있습니다. 

 

beginIndex 위치에서 시작하여 endIndex 전 위치까지의 값을 리턴 합니다. 

 

 

다음 문자열중 356512 값만 가져오는 것을 연습해 보겠습니다. 

String str = "0000003565120";
System.out.println(str.substring(6, 12));

 

 

문자열 0 0 0 0 0 0 3 5 6 5 1 2 0
 index 값 0 1 2 3 4 5 6 7 8 9 10 11 12

 

시작 인덱스 값을 6 으로 끝나는 인덱스 값을 12로 설정하여 원하는 356512 라는 값을 리턴 받을 수 있습니다. 

substring(6, 12) ==> index 6 위치에서 index 12 - 1 위치 (11 자리) 까지의 값을 리턴 합니다.

 

String str = "0000003565120";
System.out.println(str.substring(6, 13));
System.out.println(str.substring(6));

만약 위와 같이 substring(6, 13) 을 했다면?

그리고 substring(6) 을 했다면? 

결과 값은 어떻게 나올까요? 

 

예상 하시는 데로 3565120 이라는 동일한 리턴 값을 받게 됩니다. 

 

System.out.println(str.substring(6, 14));

만약 위와 같이 endIndex 값을 14로 주게 되면 어떻게 될까요? 

index 범위를 벗어나는 값을 입력 했으므로 아래와 같이 오류가 발생하게 됩니다. 

 

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 14

 

 

 

substring(int index) 보다는 substring(int beginIndex, int endIndex) 를 많이 사용 하게 되실겁니다. 

알아 두면 정말 유용하고, 꼭 알아 두어야 하는 java 함수 입니다. 

 

 

 

 도움이 되셨다면 로그인이 필요 없는 

▼ 하트 클릭 한번 부탁 드립니다 

감사합니다 :D



블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,

 

 

 

안녕하세요. 제임스 입니다. 

 

오늘은 크롬을 이용 하시는 분들이라면 보게 되는 크롬 알림 차단 하는 방법에 대해 알아 보겠습니다. 

사실, 정말 필요한 알림이 들어 오는 경우도 있지만 원치 않게, 실수로 알림을 허용 하는 경우가 있습니다. 이 경우 PC 화면 우측 하단에 알림이 들어 오는데요, 가끔 정말 이상한 알림이 오면서 당황스럽게 만들기도 합니다. 

이런 알림을 간단하게 끄거나 차단하는 방법에 대해 알아 보겠습니다. 

 

 

 

 

크롬 우측 상단 

 버튼(설정버튼)을 클릭 합니다.

 

 

 

 

설정을 클릭 하여 크롬 설정 화면으로 진입합니다.

 

 

 

 

최 하단으로 스크롤을 이동하면 고급 ▼ 버튼이 보입니다. 

클릭 해주세요~

 

 

 

 

콘텐츠 설정 버튼을 클릭 합니다.

 

 

 

 

크롬 알림 설정을 위해 알림 버튼을 클릭 합니다.

 

 

 

 

 

차단 / 허용 목록이 보입니다. 

허용 상태 목록에서 차단하고자 하는 대상을 선택 합니다.

저는 en.savefrom.net 을 차단해 보겠습니다.

 

 

 

 

목록 우측 

 버튼 (설정버튼)을 클릭 합니다.

차단 / 수정 / 삭제 항목이 보입니다.

차단을 선택하여 해당 항목을 차단 합니다.

 

 

 

 

차단 목록에 해당 항목이 보여 집니다. 

 

 

 

 

간단한 Tip 이지만 아주 유용한 팁이죠~ ^^

지금 원치 않는 크롬 알림에서 자유로워 지세요~!!!

 

 

 

 

 도움이 되셨다면 로그인이 필요 없는 

▼ 하트 클릭 한번 부탁 드립니다 

감사합니다 :D

 

블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,

 

 

 

■ jQuery 를 이용하여 id, class, name 의 input value 값 가져오기

 

 

 

 

1
<input type="text" id="inputId" class="inputClass" name="inputName">
cs

 

 

위와 같은 input tag 가 있다고 가정 하겠습니다. 

 

이 input tag 에 id, class, name 값을 각각 지정 했습니다. 

 

1
<input type="button" onclick="getInputValue();" value="Get Value">
cs

 

버튼을 하나 만들어서 클릭 이벤트 발생 시 getInputValue() 라는 함수가 호출 되도록 했습니다. 

 

이제 getInputValue() 라는 함수를 정의해야 합니다. 

 

첫번째 input tag 의 value 값을 가져 오는 방법은 아래와 같이 세가지가 있습니다. 

 

▶ id 값 기준으로 가져 오기

var valueById = $('#inputId').val();

# 은 아이디를 의미

 

▶ class 값 기준으로 가져 오기

var valueById = $('.inputClass').val();

. 은 클래스를 의미

 

▶ name 값 기준으로 가져 오기

var valueById = $('input[name=inputName]').val();

 

 

위와 같은 방법으로 id, class, name 별로 값을 가져 올 수 있습니다. 

 

 

실제 호출 하는 예제를 보시겠습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
<script type="text/javascript">
    function getInputValue(){
        var valueById = $('#inputId').val();
        var valueByClass = $('.inputClass').val();
        var valueByName = $('input[name=inputName]').val();
            
        alert('valueById = ' + valueById +
                '\nvalueByClass = ' + valueByClass +
                '\nvalueByName = ' + valueByName);
    }
</script>
cs

 

 

위 코드들을 이용 하면 아래와 같은 결과물을 보실 수 있습니다.

 

 

 

 

 

 

input 에 값을 입력 후 Get Value 버튼을 클릭 하시면 입력된 값이 리턴 되는 것을 확인 할 수 있습니다. 

 

 

 

 도움이 되셨다면 로그인이 필요 없는 

▼ 하트 클릭 한번 부탁 드립니다 

감사합니다 :D

블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,

 

삼성 갤럭시를 필두로 한 안드로이드 스마트폰에서 카카오톡, 카카오페이지, 네이버, 각종 게임 등 일부 앱들이 실행 중 오류 발생하며 강제 종료되는 현상이 발견되었습니다. 

 

이는 구글 시스템 앱 중 하나인 Android System Webview (Android 시스템 Webview) 라는 앱 문제라고 합니다. 

명확한 원인은 밝혀 지지 않은 상태라고 하는데요.

 

해결하는 방법은 있습니다. 

 

 

 

설정 버튼을 클릭 합니다.

 

 

애플리케이션을 클릭합니다. 

 

 

Android System Webview 를 선택합니다.

한글로 표기되는 경우 Android 시스템 Webview 라고 나옵니다. 

이미지에서 바로 아래 하나 더 있는 건 투폰 서비스 이용 중이기 때문이니 무시하세요 ^^

 

 

 

점 세 개로 구성된 설정 버튼을 클릭합니다. 

 

 

 

업데이트 삭제를 클릭 합니다.

 

 

 

저런 안내가 있지만, 실제 거의 영향도가 없습니다. 

무시하고 확인을 클릭해줍니다. 

 

 

 

업데이트 삭제 완료 후 휴대폰을 재시작해줍니다. 

 

 

 

 

휴대폰이 재시작되고 나면 모은 것이 다시 정상화되어 있음을 확인할 수 있습니다. 

 

 

 

구글에서 배포한 잘못된 앱 업데이트 하나로 많은 사람들이 고생을 하게 되었습니다. 

빨리 수정판 업데이트가 나왔으면 좋겠습니다. 

 

간략히 위 절차를 다시 정리하자면 아래와 같습니다. ^^

 

설정 > 애플리케이션 > Android System Webview > 업데이트 삭제 > 휴대폰 재시작 > 모든 앱 정상 이용 가능

 

 

 

 

 

 

 도움이 되셨다면 로그인이 필요 없는 

▼ 하트 클릭 한번 부탁드립니다 

감사합니다 :D

 

블로그 이미지

쉬운코딩이최고

Android, Java, jsp, Linux 등의 프로그래밍 언어를 소개 합니다.

,