Integer는 null 입력이 가능하다.

 

Integer 변수에 null이 입력되었을 경우

if문으로 숫자와 비교했을 때 바른 문법이라고 생각했다.

그러나, Integer에 null이 입력했을 경우 숫자와 비교했을 때 아래와 같은 에러가 발생하였다.

습관적으로

NullPointerException이 발생하여 num1에 null이 입력되어 발생하는 줄로만 인식하였다.

그렇다면, 처음 변수 선언하는곳에서 에러가 발생해야 하는게 아닌가?

Integer 변수에 null이 입력되어 발생하는게 아니라,

null과 정수(int 자료형)를 비교하려고 하기 때문에 발생하는 에러였다.

 

아래를 살펴보자.

정수와 null을 비교해보자. 아예 int와 null 타입자체를 비교할 수 없다고 에러가 발생한다.

 

 

 

습관은 무서운 것이다.

항상, 한 발 물러서서 접근하는 자세가 필요하다.

 

빅쿼리(Big Query) 연동하는 방법을 소개하겠습니다.

 

Spring-boot의 Maven을 사용하였고,

 

인증방법은 Credentials로 사용자 인증 정보가 담긴 json파일로 하였습니다.

 

pom.xml에 다음과 같이 추가합니다.

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>libraries-bom</artifactId>
      <version>26.0.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>com.google.cloud</groupId>
    <artifactId>google-cloud-bigquery</artifactId>
  </dependency>
</dependencies>

 

프로젝트 resources 내에 사용자 인증 정보의 json파일을 업로드합니다.

resources/keys/credentials.json

 

BigQuery를 생성합니다.

package com.study.common.api.google.biquery;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.cloud.bigquery.*;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileInputStream;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * 구글 빅쿼리
 */
public class ApiBigQueryAuthentication {

    /**
     * 구글 credentials.json을 통한 Biquery 생성
     * @return {BigQuery}
     */
    public static BigQuery getBigQuery() {
        try {
            // credentials.json 파일을 읽는다.
            File credentialsFile = ResourceUtils.getFile("classpath:keys/credentials.json");
            GoogleCredentials credentials;
            try (FileInputStream fileInputStream = new FileInputStream(credentialsFile)) {
                credentials = ServiceAccountCredentials.fromStream(fileInputStream);
            }
            
            // BigQuery 생성
            BigQuery bigQuery = BigQueryOptions.newBuilder()
            	.setCredentials(credentials)
                // credentials.json에 있는 project_id
                .setProjectId("project_id")
            	.build()
                .getService()
            ;
            return bigQuery;
        } catch (Exception e) {
            return null;
        }
    }
}

 

TableResult를 반환하는 메서드를 생성합니다.

/**
 * BigQuery 수행 및 결과
 * @param {String} query
 * @throws {Exception}
 * @return {TableResult}
 */
 public static TableResult bigQueryExecute(String query) throws Exception {
     BigQuery bigQuery = getBigQuery();
     
     QueryJobConfiguration queryJobConfiguration = 
         // Query
         QueryJobConfiguration.newBuilder(query)
             // 표준 SQL 사용
             // See: https://cloud.google.com/bigquery/sql-reference/
             setUseLegacySql(false)
         .build();
     
     // 보안문제로 JobId 생성
     JobId jobId = JobId.of(UUID.randomUUID().toString());
     Job job = bigQuery.create(JobInfo.newBuilder(queryJobConfiguration).setJobId(jobId).build());
     
     // 쿼리가 완성될 동안 대기
     job = job.waitFor();
     
     // 예외처리
     if (job == null) {
         throw new RuntimeException("쿼리가 존재하지 않습니다.");
     } else {
         if (job.getStatus().getError() != null) {
             String errorMessage =
                 job.getStatus().getError().getMessage() + "\n"
               + job.getStatus().getError().getReason() + "\n"
               + job.getStatus().getError().toString()
             ;
             throw new RuntimeException(errorMessage);
         } else {
             TableResult tableResult = job.getQueryResults();
             return tableResult;
         }
     }
 }

 

bigQueryExecute를 이용하여 TableResult를 받은 후 List<Map<String, Object>>에 넣어보겠습니다.

/**
 * 빅쿼리 조회
 * @return {List<Map<String, Object>>}
 * @throws {Exception}
 */
public List<Map<String, Object>> selectBigQuery() throws Exception {
    StringBuffer stringBuffer = new StringBuffer();
    stringBuffer.append("SELECT 'green' AS color     ");
    stringBuffer.append("    ,  '초록'  AS colorNm   ");
    stringBuffer.append("  FROM DUAL                 ");
    stringBuffer.append(" UNION ALL                  ");
    stringBuffer.append("SELECT 'pink'  AS color     ");
    stringBuffer.append("    ,  '분홍'  AS colorNm   ");
    stringBuffer.append("  FROM DUAL                 ");
    
    TableResult tableResult = bigQueryExecute(stringBuffer.toString());
    // TableResult를 담을 List 생성
    List<Map<String, Object>> dataList = new ArrayList<Map<String, Object>>();
    // List에 add할 map 선언
    Map<String, Object> map;
    
    int idx = 1;
    // tableResult for start
    for (FieldValueList fieldValueList:tableResult.iterateAll()) {
        // map 초기화
        map = new HashMap<String, Object>();
    
        // idx 초기화
        idx = 1;
        // FieldValueList for start
        for (FieldValue fieldValue:FieldValueList) {
            // Column의 Alias명은 알 수 없음.
            // 내가 선언한 쿼리의 순서를 인지하고 Map의 key를 알맞게 넣어줘야 함.
            if (idx == 1) map.put("color", fieldValue.getStringValue());
            
            if (idx == 2) map.put("colorNm", fieldValue.getStringValue());
            
            idx++;
        } // FieldValueList for end
        
        // list add
        dataList.add(map);
        
    } // tableResult for end
    return dataList;
}

 

 

 

공통 메서드 중 가장많이 사용하는 isEmpty 메서드를 소개한다.

 

null or not null 을 먼저 판별한 후

 

각 어떤 클래스인지 instanceof로 판단 뒤 각 클래스에 선언된 메서드를 이용하여 판별한다.

 

Java isEmpty 메서드

/**
 * obj가 null 혹은 비어있는지 비교
 * 
 * @params Object obj
 * @return boolean
 * @apiNote Custom.isEmpty(obj)
 *
 */
public static boolean isEmpty(Object obj){
    // null 이라면
    if (obj == null)
        return true;

    // String 이라면
    if (obj instanceof String)
        return ("".equals(((String) obj).trim()));

    // Map이라면
    if (obj instanceof Map)
        return ((Map<?,?>) obj).isEmpty();

    // List라면
    if (obj instanceof List)
        return ((List<?>) obj).isEmpty();

    // Object 배열이라면..
    if (obj instanceof Object[])
        return (((Object[]) obj).length == 0);

    return false;
}

 

프로젝트 중 문자 전송 관련하여 개발했을 때,

 

문자 내용 길이에 따라, SMS/LMS/MMS 기준으로 전송해야할 때가 있었다.

 

웹 검색 중 Byte 계산에 대한 1byte, 2byte 등 기준이 애매한게 많았다.

 

숫자, 영문, 띄어쓰기, 줄바꿈 등은 1byte

 

한글, 특수문자 등은 2byte로 계산하는것을 작성하였고, 추후에 필요할까 싶어 기록해놓는다.

 

public static int getByteLength(String str) {
    int bytes = 0;
    if (str == null) {

        return bytes;

    } else {

        char[] strChar = str.toCharArray();
        char ch; int code;

        for (int i = 0; i < strChar.length; i++;) {
            ch = strChar[i];
            code = (int) ch;

            // 2bytes
            if ((ch < '0' || ch > '9') && (ch < 'A' || ch > 'Z') && code > 255) bytes += 2;
            // 1bytes
            else bytes +=1;
        }

        return bytes;

    }
}

 

 

Byte 계산 (영문, 숫자, 공백 = 1byte, 그 이외 한글, 한문, 특수문자 등 = 2byte)

 

+ Recent posts