Iterables.concat()는 여러 리스트를 하나의 리스트로 합치는 기능을 가진다.



final List<Integer> list1  = Lists.newArrayList(1, 2, 3);

final List<Integer> list2 = Lists.newArrayList(100, 200, 300);


System.out.println(Iterables.concat(list1, list2));



결과

[1, 2, 3, 100, 200, 300]




기억할 필요가 있는 것은 타입이 달라도 하나로 합칠 수 있다는 점이다. 




final List<String> list1  = Lists.newArrayList("a", "b", "c");

final List<Integer> list2 = Lists.newArrayList(4, 5, 6);


System.out.println(Iterables.concat(list1, list2));




결과

[a, b, c, 4, 5, 6]



Posted by '김용환'
,



자바에서 객체의 toString()을 구현하는 여러 방법이 있다.





1. 그냥 java를 이용하기



class Member {

  public int id;

  public String name;

  @Override

  public String toString() {

    return "[Member]:" + id + "," + name;

  }

}


Member member = new Member();

member.id = 1;

member.name = "samuel";

System.out.println(member);




결과

[Member]:1,samuel




2. apache commons의 ReflectionToStringBuilder를 사용할 수 있다. 

hashcode와 full-qualified-classname도 동시에 보여주기 때문에 좀 길어진다는 단점이 있다. 


import org.apache.commons.lang.builder.ReflectionToStringBuilder;

...


class Member {

  public int id;

  public String name;

  @Override

  public String toString() {

    return ReflectionToStringBuilder.toString(this);

  }

}


Member member = new Member();

member.id = 1;

member.name = "samuel";

System.out.println(member);



결과

full-qualified-클래스이름$Member@6fadae5d[id=1,name=samuel]



3. apache commons의 ToStringBuilder와 TStringStyle을 사용할 수 있다. 


import org.apache.commons.lang.builder.ToStringBuilder;

import org.apache.commons.lang.builder.ToStringStyle;

..

class Member {

public int id;

public String name;


@Override

public String toString() {

return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);

}

}


Member member = new Member();

member.id = 1;

member.name = "samuel";

System.out.println(member);


apache commons의 ReflectionToStringBuilder의 결과보다 깔끔하다.


결과
Member[id=1,name=samuel]



4. guava의 Objects 클래스의 toStringHelper()를 사용할 수 있다. 

apache commons보다 깔끔히 사용할 수 있다. 가장 깔끔하기 때문에, 쓰는 것을 추천한다. 



import com.google.common.base.Objects;

..

class Member {

public int id;

public String name;

@Override

public String toString() {

return Objects.toStringHelper(this)

            .addValue(this.id)

            .addValue(this.name)

            .toString();

}

}


Member member = new Member();

member.id = 1;

member.name = "samuel";

System.out.println(member);



결과

Member{1, samuel}





참고로 Objects 클래스에는 hashcode로 예쁘게 만들 수 있다. 




class Member {

public int id;

public String name;


@Override

  public int hashCode() {

return Objects.hashCode(this.id, this.name);

}


@Override

public String toString() {

return Objects.toStringHelper(this)

            .addValue(this.id)

            .addValue(this.name)

            .toString();

}

}


Member member = new Member();

member.id = 1;

member.name = "samuel";

System.out.println(member);

System.out.println(member.hashCode());



결과


Member{1, samuel}

-909669507




참고로.


Objects 클래스의 중요 메소드는 Objects에서 MoreObjects로 바꿔써야 한다. Objects의 중요 메소드는 2016년 6월부터 모두 deprecated된다. 


http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Objects.html

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/MoreObjects.html

Posted by '김용환'
,




특정 변수 값을 반드시 보장하기 위한 테스트 방법을 소개한다.


1. if와 IllegalArgumentException를 많이 사용한다.


@Test

public void test() {

int number = -1;

    if (number <= 0) {

      throw new IllegalArgumentException("must be positive: " + number);

    }

}


//결과

//java.lang.IllegalArgumentException: must be positive: -1




2. assert 사용

c, c++을 썼던 아저씨 세대들이 자주 사용하는 패턴이다. -ea, -da를 사용하여 assert를 테스트한다. 


int number = -1;

assert number > 0;




3. 1 번처럼 동일하게 쓰되 Guava의 Preconditions 클래스의 사용


http://guava-libraries.googlecode.com/svn-history/r14/trunk/javadoc/com/google/common/base/Preconditions.html



@Test

public void test() {

int number = -1;

Preconditions.checkArgument(number > 0, "must be positive: %s", number);

}


//결과

//java.lang.IllegalArgumentException: must be positive: -1



Posted by '김용환'
,


2.3.19 버전 이하의 freemarker를 쓰는 사용자라면, freemarker의 boolean을 사용할 때 유의해야 한다.


member라는 객체의 boolean 변수를 사용할 때는  ${member.vip?string("Yes", "No")}라 써야 한다.


${member.vip?c} 로 표현하면, boolean 변수 표현에 대해 문자열이 아니다고 에러가 발생한다.


freemarker.core.NonStringException:

Expecting a string, date or number here, Expression profile.vip is instead a freemarker.template.TemplateBooleanModel$2





그런데, 2.3.20부터  ${member.vip?c} 와 같이 사용가능하다.


그리고  ${member.vip?string} 는 deprecated 되었다.




또한, 2.3.23 부터 ${member.vip?string("yes", "no")}은 deprecated 되었다.

대신, ${member.vip?then("yes", "no")}으로 변경해야 한다. 

(참고로 숫자는 switch? 를 사용한다.)




참고 :

http://freemarker.org/docs/ref_builtins_boolean.html




Posted by '김용환'
,



Iterables.limit() 메소드는 리스트의 개수를 주어진 개수만큼만 잘라 리턴한다.

List<String> list = new ArrayList<String>() { { add("1");add("2");add("3"); } };
List<String> newList = Lists.newArrayList(Iterables.limit(list, 1));
System.out.println(newList);

결과


[1]



좀 더 고급스럽게 쓰려면 다음과 같이 사용한다.


limit 메소드를 정의하여 크기의 개수를 통제하여 List를 리턴한다.

public static <E> List<E> limit(List<E> list, int size) {
if (list == null) {
return Collections.emptyList();
}
return Lists.newArrayList(Iterables.limit(list, size));
}


동작 코드는 다음과 같다.

List<String> list = new ArrayList<String>() { {add("1");add("2");add("3"); } };
List limited = limit(list, 2);
System.out.println(limited);


결과

[1]

Posted by '김용환'
,


java 1.1부터 instance initializer, instance initialization block이라는 것이 있다.

클래스에서 { } 로 묶여진 블럭을 의미한다. 인스턴스 생성시 호출된다.


class Member {
public String id; // instance initializer block
{
id = "id";
System.out.println(id);
} //... }



이를 좀 응용해서 anonymous class init 코드에 instance initializer를 넣어 간단하게 List를 구현하는 코드를 생성할 수 있다.


List<String> list = new ArrayList<String>() { { add("a");add("b");add("c"); } };

List<String> list = new ArrayList<String>() {
{
add("a");
add("b");
add("c");
}
};




Posted by '김용환'
,



* 젠킨스(jenkins) 잡에 대한 정보 받기


http://장비이름:8080/job/잡이름/api/json

http://장비이름:8080/job/잡이름/api/xml


상황에 따라 너무 많이 나오니. depth 매개변수를 사용하여 적당히 잘라낼 수 있다. 


http://장비이름:8080/job/잡이름/api/json?depth=1

http://장비이름:8080/job/잡이름/api/json?depth=2





* 젠킨스(jenkins) 잡이 현재 실행 중인 확인하기


http://장비이름:8080/job/잡이름/lastBuild/api/json 

http://장비이름:8080/job/잡이름/lastBuild/api/xml


json으로 확인하려면 http://장비이름:8080/job/잡이름/lastBuild/api/json 을 호출 후, building 프로터의 값을 확인할 수 있다. True이면 job이 동작 중이고, False이면 job이 실패 중이다. 


파이썬 코드로 설명하면 다음과 같다.



import json

import urllib2


is_job_working = json.load(urllib2.urlopen("http://장비이름:8080/job/잡이름/lastBuild/api/json"))['building'] 

if (is_job_working == True) {

...

}





Posted by '김용환'
,



apache common의 BooleanUtils는 쓸 때 없는 api가 많긴 하지만, 괜찮은 api 가 2 개 정도 있다.

 BooleanUtils.toBoolean()과  BooleanUtils.toBooleanDefaultIfNull()이 존재한다.



- BooleanUtils.toBoolean()은 String 타입의 boolean 값을 변환한다. toBoolean()의 결과 중 true, false로 변환할 수 있는 문자열을 제외하고는 모두 false를 리턴한다.

@Test
public void booleanUtilsTest() {
System.out.println(BooleanUtils.toBoolean("true"));
System.out.println(BooleanUtils.toBoolean("false"));
System.out.println(BooleanUtils.toBoolean(""));
System.out.println(BooleanUtils.toBoolean("aaa"));
}

결과


true

false

false

false




참고로.. BooleanUtils.toBoolean()의 내부 구현체이다.

public static boolean toBoolean(Boolean bool) {
if (bool == null) {
return false;
}
return bool.booleanValue() ? true : false;
}





하지만, toBooleanDefaultIfNull()는 null 값에 대해 값을 명시할 수 있다. 예를 들어, null이면 false가 아닌 true로 리턴할 수 있다.


@Test
public void booleanUtilsTest() {
System.out.println(BooleanUtils.toBooleanDefaultIfNull(Boolean.TRUE, true));
System.out.println(BooleanUtils.toBooleanDefaultIfNull(Boolean.FALSE, false));
System.out.println(BooleanUtils.toBooleanDefaultIfNull(null, true));
}

결과

true

false

true


내부 구현은 다음과 같다.


public static boolean toBooleanDefaultIfNull(Boolean bool, boolean valueIfNull) {
if (bool == null) {
return valueIfNull;
}
return bool.booleanValue() ? true : false;
}





 BooleanUtils.toBoolean()과  BooleanUtils.toBooleanDefaultIfNull()에 관련된 예시 코드이다. 


@Test
public void exceptionTest() {
List<Member> members = Lists.newArrayList();
members.add(new Member("1", true));
members.add(new Member(null, null));
members.add(new Member("3", false));

System.out.println("== first - NPE");
try {
for (Member member : members) {
if (true == member.followable) { // NPE!!
System.out.println(member.id);
}
}
} catch (Exception e) {
e.printStackTrace();
}

System.out.println("== second chance using BooleanUtils - exclude null");
for (Member member : members) {
if (!BooleanUtils.toBoolean(member.followable)) {
System.out.println(member.id + "," + member.followable);
}
}

System.out.println("== another chance - exclude null, true");
for (Member member : members) {
if (member.followable != null && member.followable == false) {
System.out.println(member.id + "," + member.followable);
}
}

System.out.println("== another chance using BooleanUtils- exclude null, true");
for (Member member : members) {
if (!BooleanUtils.toBooleanDefaultIfNull(member.followable, true)) {
System.out.println(member.id + "," + member.followable);
}
}

}


결과


== first - NPE

1

java.lang.NullPointerException

at com.google.NullElementTest.exceptionTest(NullElementTest.java:24)

== second chance - exclude null

null,null

3,false

== another chance - exclude null, true

3,false

== another chance using BooleanUtils- exclude null, true

3,false



Posted by '김용환'
,



Collection에서 add나 remove를 할 때, loop 안에서 작업하면 CME 가 발생할 수 있다.


@Test
public void exceptionTest() {
List<Member> members = Lists.newArrayList();
members.add(new Member("1", "true"));
members.add(null);
members.add(new Member("3", "false"));

for (Member member : members) {
if (member == null) {
members.remove(member);
members.add(new Member("4", "true")); // 여기서 CME 발생
}
}

System.out.println(members.size());
}

결과

java.util.ConcurrentModificationException

at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)

at java.util.ArrayList$Itr.next(ArrayList.java:851)

at com.google.NullElementTest.exceptionTest(NullElementTest.java:20)







Collection에서 null 인 엘리먼트를 삭제하려면, Collections.removeAll()을 사용할 수 있다.

바로 Collections.removeAll(null)을 호출하면, cme가 발생한다.


따라서, 이를 해결하려면, Collection을 하나 만들고 null 엘리먼트를 추가한 후, members.removeAll(리스트)를 호출한다.

@Test
public void avoidNpeTest() {
List<Member> members = Lists.newArrayList();
members.add(new Member("1", "true"));
members.add(null);
members.add(new Member("3", "false"));

// members.removeAll(null); // error

List<Member> nullList = Lists.newArrayList();
nullList.add(null);
members.removeAll(nullList);

System.out.println(members);
}


결과


[com.google.NullElementTest$Member@2133c8f8[id=1,followable=true], com.google.NullElementTest$Member@3ac3fd8b[id=3,followable=false]]




조금 verbose하니, Collections.singleton(null)을 이용하면 이전 예시와 동일한 결과를 얻을 수 있다.


@Test
public void avoidElegantNpeTest() {
List<Member> members = Lists.newArrayList();
members.add(new Member("1", "true"));
members.add(null);
members.add(new Member("3", "false"));

System.out.println(Collections.singleton(null));

members.removeAll(Collections.singleton(null));
System.out.println(members);
}


결과


[null]

[com.google.NullElementTest$Member@2133c8f8[id=1,followable=true], com.google.NullElementTest$Member@3ac3fd8b[id=3,followable=false]]








참고 : 코드 전문


package com.google;

import com.clearspring.analytics.util.Lists;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.util.Collections;
import java.util.List;

public class CMETest {

@Test
public void exceptionTest() {
List<Member> members = Lists.newArrayList();
members.add(new Member("1", "true"));
members.add(null);
members.add(new Member("3", "false"));

for (Member member : members) {
if (member == null) {
members.remove(member);
members.add(new Member("4", "true"));
}
}

System.out.println(members.size());
}

@Test
public void avoidNpeTest() {
List<Member> members = Lists.newArrayList();
members.add(new Member("1", "true"));
members.add(null);
members.add(new Member("3", "false"));

// members.removeAll(null); // error

List<Member> nullList = Lists.newArrayList();
nullList.add(null);
members.removeAll(nullList);

System.out.println(members);
}

@Test
public void avoidElegantNpeTest() {
List<Member> members = Lists.newArrayList();
members.add(new Member("1", "true"));
members.add(null);
members.add(new Member("3", "false"));

System.out.println(Collections.singleton(null));

members.removeAll(Collections.singleton(null));
System.out.println(members);
}

class Member {
public String id;
public String followable;

public Member(String id, String f) {
this.id = id;
this.followable = f;
}

public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
}


Posted by '김용환'
,


Guava의 Predicate과 Filter를 이용하여

List에서 Member의 특정 필드의 값이 false이면 , List에서 제외하는 예시이다.

package com.google;

import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.junit.Test;

import java.util.List;

public class GuavaFilterTest {

@Test
public void PredicateTest() {
List<Member> members = ImmutableList.<Member>builder()
.add(new Member("1", "true"))
.add(new Member("2", "true"))
.add(new Member("3", "false"))
.build();

Predicate<Member> predicate = new Predicate<Member>() {
@Override
public boolean apply(Member input) {
return BooleanUtils.toBoolean(input.followable);
}
};

List<Member> newMembers = FluentIterable.from(members).filter(predicate).toList();
System.out.println(newMembers);
}

@Test
public void PredicateTestWithJava8() {
List<Member> members = ImmutableList.<Member>builder()
.add(new Member("1", "true"))
.add(new Member("2", "true"))
.add(new Member("3", "false"))
.build();

List<Member> newMembers = FluentIterable.from(members)             .filter(s -> BooleanUtils.toBoolean(s.followable)).toList();
System.out.println(newMembers);
}

class Member {
public String id;
public String followable;

public Member(String id, String f) {
this.id = id;
this.followable = f;
}

public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
}


결과


[com.google.IterableTest$Member@3b81a1bc[id=1,followable=true], com.google.IterableTest$Member@13fee20c[id=2,followable=true]]

[com.google.IterableTest$Member@32d992b2[id=1,followable=true], com.google.IterableTest$Member@215be6bb[id=2,followable=true]]


Posted by '김용환'
,