스칼라와 자바의 람다식 표현 중 주요 차이점을 설명한다. 


스칼라는 block({, }) 지정이 자유로운 편이다.


scala> (1 to 3).map(i => i * 2).foreach(println)

2

4

6


scala> (1 to 3).map(i => {i * 2}).foreach(println)

2

4

6



그러나 자바의 경우는 block 지정이 자유롭지 않다.


Stream.of(1,2,3).map(i -> i * 2).forEach(System.out::println);

2

4

6



Stream.of(1,2,3).map(i -> {i * 2}).forEach(System.out::println);

// 컴파일 에러


Stream.of(1,2,3).map(i -> {i * 2;}).forEach(System.out::println);

// 컴파일 에러



코드를 다음처럼 리턴문을 추가된 상태로 변경해야 한다.


Stream.of(1,2,3).map(i -> {return i*2;}).forEach(System.out::println);

2

4

6


Posted by 김용환 '김용환'

댓글을 달아 주세요

java의 volatile

java core 2017. 4. 17. 10:08


java의 volatile 타입은 다음과 같이 정의되어 있다. 


https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4



8.3.1.4. volatile Fields


The Java programming language allows threads to access shared variables (§17.1). As a rule, to ensure that shared variables are consistently and reliably updated, a thread should ensure that it has exclusive use of such variables by obtaining a lock that, conventionally, enforces mutual exclusion for those shared variables.


The Java programming language provides a second mechanism, volatile fields, that is more convenient than locking for some purposes.


A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable (§17.4).





소스에서 자바의 volatile을 잘 만날 수 없는 요인 중에 하나는 자바 concurrent package의 클래스가 자바의 volatile을 감싸고 있기 때문이다. 



예를 들어  AtomicInteger의 내부를 살펴본다. value 값에 대해서 volatile라고 선언되어 있다. 


http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/atomic/AtomicInteger.java




51 

52 public class AtomicInteger extends Number implements java.io.Serializable {

53     private static final long serialVersionUID = 6214790243416807050L;

54 

55     // setup to use Unsafe.compareAndSwapInt for updates

56     private static final Unsafe unsafe = Unsafe.getUnsafe();

57     private static final long valueOffset;

58 

59     static {

60       try {

61         valueOffset = unsafe.objectFieldOffset

62             (AtomicInteger.class.getDeclaredField("value"));

63       } catch (Exception ex) { throw new Error(ex); }

64     }

65 

66     private volatile int value;



    

72 

73     public More ...AtomicInteger(int initialValue) {

74         value = initialValue;

75     }




Posted by 김용환 '김용환'

댓글을 달아 주세요





java7에서 java8로 전환할 때 

특정 인터페이스가 하나의 메소드를 가지고 있을 때(포맷에 맞아야 함, Callable처럼) 깔끔히 처리될 수 있다. 


1) Callable(java.util.concurrent.Callable)을 쉽게 정리할 수 있다.




기존 코드


Callable<List<Help>> callable = new Callable<List<Help>>() {

@Override

public List<Help> call() throws Exception {

return jdbcTemplate.query("select id from helps");

}

};



return cacheTemplate.gets(CACHE_HELPS, callable, Help.class);




->

새코드 

return cacheTemplate.gets(CACHE_HELPS, () -> {jdbcTemplate.query("select id from helps"); }, Help.class);






2) Runnable을 쉽게 정리할 수 있다.

 

기존 코드 

class MyRunnable implements Runnable {

List<FeedItem> myFeedItems;

public MyRunnable(List<FeedItem> feedItems) {

myFeedItems = feedItems;

}


@Override

public void run() {

saveFeedStat(myFeedItems);

}

}


public void saveFeedStatAsync(final List<FeedItem> feedItems) {

Runnable worker = new MyRunnable(feedItems);

executor.execute(worker);

}


 

=>

새 코드 

public void saveFeedStatAsync(final List<FeedItem> feedItems) {

Runnable talk = () -> { saveFeedStat(feedItems); };

executor.execute(talk);

}




3) 하나의 인터페이스를 가진 interface에 FunctionalInterface를 사용할 수 있다. 


기존 코드



public interface MessageCallable<T, V> {

List<V> call(Collection<T> ids);

}


    

public List<Message> findAll() {

Callable<List<Message>> callable = new MessageCallable<List<Message>>() {

@Override

public List<Message> call() throws Exception {

return _findAll();

}

};

return cacheTemplate.gets(CACHE_MESSAGE, callable, Message.class);

}


=>


새로운 코드 


@FunctionalInterface

public interface MessageCallable<T, V> {

List<V> call(Collection<T> ids);

}


 

public List<EmoticonMessage> findAll() {

return cacheTemplate.gets(MESSAGE, () -> {return _findAll();}, Message.class);

}




4) Guava 코드도 쉽게 정리할 수 있다.


List<String> activityIds = Lists.transform(items, new Function<ActionGraphItemParsed, String>() {

@Override

public String apply(ActionGraphItemParsed item) {

return item.activityId;

}

});


->



List<String> activityIds = Lists.transform(items, (ActionGraphItemParsed item) -> {

return item.activityId;

});



또 다른 예시이다.



public static final Predicate<String> BLANK_STRING_FILTER = new Predicate<String>() {

@Override

public boolean apply(String url) {

return StringUtils.isNotBlank(url);

}

};

-> 

public static final Predicate<String> BLANK_STRING_FILTER = (String url) -> {

return StringUtils.isNotBlank(url);

};











Posted by 김용환 '김용환'

댓글을 달아 주세요




java7 이하에서는 Callable 메소드를 생성하면 다음과 같은 형식으로 개발했다. 



import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

...


                 String text = "1";

Callable<Integer> task = new Callable<Integer>() {

@Override

public Integer call() throws Exception {

return Integer.parseInt(text);

}

};


FutureTask<Integer> futureTask = new FutureTask<Integer>(task);

futureTask.run();

try {

System.out.println(futureTask.get());

} catch (Exception e) {

e.printStackTrace();

}




java8에서는 Callable의 call을 람다표현으로 깔끔하게 구성할 수 있다. 



import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

...

String text = "1";

FutureTask<Integer> futureTask = new FutureTask<Integer>(() -> {

return Integer.parseInt(text);

});

futureTask.run();

try {

System.out.println(futureTask.get());

} catch (Exception e) {

e.printStackTrace();

}





그 이유는 java에서 @FunctionalInterface를 사용하는 코드는 알아서 람다 표현식으로 사용할 수 있게 한다.


@FunctionalInterface

public interface Callable<V> {

    /**

     * Computes a result, or throws an exception if unable to do so.

     *

     * @return computed result

     * @throws Exception if unable to compute a result

     */

    V call() throws Exception;

}


 

Runnable도 동일하다. 


@FunctionalInterface

public interface Runnable {

    /**

     * When an object implementing interface <code>Runnable</code> is used

     * to create a thread, starting the thread causes the object's

     * <code>run</code> method to be called in that separately executing

     * thread.

     * <p>

     * The general contract of the method <code>run</code> is that it may

     * take any action whatsoever.

     *

     * @see     java.lang.Thread#run()

     */

    public abstract void run();

}



비슷하게 Runable을 테스트해본다.



Runnable runabble = new Runnable() {

  @Override

  public void run() {

  System.out.println("Run!!");

  }

};

Thread th = new Thread(runabble);

th.start();

   Thread.sleep(1000);



위의 코드와 아래 코드는 동일하다. 


                Thread th = new Thread(() -> {

System.out.println("Run!!");

});

th.start();

              Thread.sleep(1000);





java8의 functional interface는 java language spec(https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.8)에서 정의되어 있고 오직 하나의 abstract method으로 구성된다.


Invalid '@FunctionalInterface' annotation; ... is not a functional interface가 뜬다면 잘못 functional interface를 정의했다는 것을 컴파일에러로 알려준다. 



FunctionalInterface를 사용자 정의 선언을 할 수 있다. 


@FunctionalInterface

interface BindCallable {

public List<String> bind();

}


class Bind {

  public List<String> process(BindCallable callable){

    return callable.bind();

  }

}



간단한 예시이다. 


Bind bind = new Bind();

List<String> result = bind.process(() -> {

final String a = "a";

final String b = "b";

List<String> list = Lists.newArrayList();

list.add(a); list.add(b);

return list;

});

System.out.println(result);




Posted by 김용환 '김용환'

댓글을 달아 주세요

이젠 cms를 java9에서 못 볼 듯...



http://openjdk.java.net/jeps/214


DefNew + CMS       : -XX:-UseParNewGC -XX:+UseConcMarkSweepGC
ParNew + SerialOld : -XX:+UseParNewGC
ParNew + iCMS      : -Xincgc
ParNew + iCMS      : -XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC
DefNew + iCMS      : -XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC -XX:-UseParNewGC
CMS foreground     : -XX:+UseCMSCompactAtFullCollection
CMS foreground     : -XX:+CMSFullGCsBeforeCompaction
CMS foreground     : -XX:+UseCMSCollectionPassing


Posted by 김용환 '김용환'

댓글을 달아 주세요

jnr

java core 2017. 2. 27. 12:01



jni, jna 다음으로 새로 나온 jnr이다. 

cassandra의 java driver에 쓰인다고 해서 보고 있다.


https://www.slideshare.net/skrb/jnr-java-native-runtime


JNR: Java Native Runtime from Yuichi Sakuraba




다른 참조 자료이다. 


http://www.oracle.com/technetwork/java/jvmls2013nutter-2013526.pdf


'java core' 카테고리의 다른 글

람다를 활용한 java8의 Callable, Runnable 예제  (0) 2017.03.27
java9에서 사라지는 gc  (0) 2017.03.20
jnr  (0) 2017.02.27
enum 데이터를 리스트(list)로 얻기  (0) 2016.12.19
[java] Map을 출력하기  (0) 2016.12.13
자바의 clone, guava의 Maps, Lists 사용  (0) 2016.12.01
Posted by 김용환 '김용환'

댓글을 달아 주세요


enum를 리스트로 얻는 방법이다.


우선 enum에서 각 entry를 읽어오려면, enum 클래스의 values() 메소드를 호출한다.



java8 이전과 이후로 나눠진다. java8은 stream(Stream.of)으로 처리하기 쉽다.



enum Direction {

north,

east,

south,

west

}




              for (Direction direction : Direction.values()) {

System.out.println(direction);

}

for (Direction direction : EnumSet.allOf(Direction.class)) {

System.out.println(direction);

}

Stream.of(Direction.values()).forEach(System.out::println);




enum에 생성자를 주어 따로 상태(필드) 값을 가질 때, enum 이름과 상태 값을 다음과 같이 얻을 수 있다. 



enum Directions {

north(10),

east(12),

south(13),

west(14);

private int no;

private Directions(int number) {

this.no = number;

}

public int getNumber() {

return no;

}

}


// java 8 이전

List<String> list = Lists.newArrayList();

for (Directions directions : Directions.values()) {

list.add(directions.name());

}

System.out.println(list);

List<Integer> list1 = Lists.newArrayList();

for (Directions directions : Directions.values()) {

list1.add(directions.getNumber());

}

System.out.println(list1);

// java 8 이후

         List<String> list3 = Stream.of(Direction.values())

    .map(Enum::name)

    .collect(Collectors.toList());

 System.out.println(list3);

  

 List list4 = Stream.of(Directions.values())

    .map(m -> m.getNumber())

    .collect(Collectors.toList());

 System.out.println(list4);

  

 

}



'java core' 카테고리의 다른 글

java9에서 사라지는 gc  (0) 2017.03.20
jnr  (0) 2017.02.27
enum 데이터를 리스트(list)로 얻기  (0) 2016.12.19
[java] Map을 출력하기  (0) 2016.12.13
자바의 clone, guava의 Maps, Lists 사용  (0) 2016.12.01
JVM의 safepoint  (0) 2016.09.08
Posted by 김용환 '김용환'

댓글을 달아 주세요


java7 이전에서 Map의 내용을 확인하기 위해 출력하는 코드는 verbose 하다.


Map<Integer,String> map = new HashMap<Integer,String>();


for(Map.Entry<Integer,String> entry: map.entrySet()){

    System.out.println(entry.getKey()+" - "+ entry.getValue());

}




Apache Collections 라이브러리는  MapUtils.debugPrint 메소드를 통해 Map을 출력할 수 있다. 이 방법은 slf4j나 log4j의 OutputStream을 얻기 어려워 쓰기 애매한 부분이 있다. 


MapUtils.debugPrint(System.out, "myMap", map);




java8부터는 stream의 forEach를 사용하면 그나마 좀 쓰기 편한 듯 하다. 



map.forEach((key, value) -> { logger.debug(key + " : " + value); });

'java core' 카테고리의 다른 글

jnr  (0) 2017.02.27
enum 데이터를 리스트(list)로 얻기  (0) 2016.12.19
[java] Map을 출력하기  (0) 2016.12.13
자바의 clone, guava의 Maps, Lists 사용  (0) 2016.12.01
JVM의 safepoint  (0) 2016.09.08
JDK의 Flight Recorder 라이선스  (0) 2016.09.08
Posted by 김용환 '김용환'

댓글을 달아 주세요


자바에서 특정 클래스를 deep copy하려면 Object#clone() 메소드를 이용한다. 


    protected native Object clone() throws CloneNotSupportedException;



public class GcmMessage {


public Object clone() throws CloneNotSupportedException {

return (GcmMessage) super.clone();

}

}


//코드

GcmMessage gcmMessage = new GcmMessage();

GcmMessage newGcmMessage = (GcmMessage ) gcmMessage.clone();



List, Map과 같은 일부 Collection은 interface이라서 clone() 메소드를 지원하지 않는다. 



이럴 때는 ArrayList 또는 HashMap같은 실제 클래스(concrete class)를 사용해야 하지만...

Guava의 Lists또는 Maps(com.google.common.collect.Maps)의 static 생성 메소드를 사용하는 것이 훨씬 편하다.

Maps.newHashMap() 또는 Lists.newArrayList()와 같은 메소드를 사용하는 것이 deep copy에 훨씬 편하다.



Map<String, Object> newMap = Maps.newHashMap(map);









Posted by 김용환 '김용환'

댓글을 달아 주세요

JVM의 safepoint

java core 2016. 9. 8. 17:33




JVM safepoint는 모든 쓰레드가 실행 상태에서 중지된 때의 시간을 의미한다. 즉, stop-the-world 중지 메커니즘이라 할 수 있다. 


safepoint는 stop-the-world 가비지 콜렉션을 포함해 전체 JVM 활동을 조정하기 위해 필요하다. 


자세한 내용은 아래 블로그를 참조한다. 간단하지만 중요한 내용이 있다. 


http://blog.ragozin.info/2012/10/safepoints-in-hotspot-jvm.html



참고로, JVM 내부에 접근하지 못하는 외부 프로파일러와 대조적으로, Flight Recorder는 JVM safepoint 바깥에서 데이터를 접근할 수 있다.



Posted by 김용환 '김용환'

댓글을 달아 주세요