split과 동시에 assign

Kotlin|2021. 11. 29. 21:02

 

val text = "a,b"
val (one,two) = text.split(",")
/*
val one = text.split(",")[0]
val two = text.split(",")[1]
*/

 

코드 작성중 신기하고 편리해보이는 문법

까먹지 않기 위해 기록

 

text.split(",")의 size가 2보다 크더라도 [0], [1] 만 assign되지만

size가 2보다 작으면 IndexOutOfBoundsException 발생함

 

댓글()

코틀린 upgrade 1.3.7 to 1.5.0

Kotlin|2021. 5. 28. 20:10

코틀린 버전이 아주 빠르게 올라가고 있습니다

마침 Jetbrains 홈페이지에서 1.5.0 출시에 대해 소식을 들을수 있었고

최근 재설계 되는 프로젝트에 맞춰 코틀린 버전업을 하면 좋을것 같아서

각 버전별 차이점을 조금씩 살펴보며 기록을 남깁니다.

(Native와 JS에 대한 내용은 살펴보지 않았습니다)

 

Version : 1.3.7, release : 20.03.03

 

표준 라이브러리에 대한 새로운 함수 및 클래스

* StringBuilder 멤버들 없던것들 추가(JVM에서는 별 영향 없을듯..)

* KClass에 대해 더이상 "kotlin-reflect"를 필요로 하지 않고, JVM에 의존적이지 않음(JVM에서는 별 영향 없을듯..)

* @Experimental @UseExperimental은 1.4 부터는 사용되지 않음, @OptIn, @RequiresOptIn으로 대체

* 시간 측정 API, Clock ClockMark 이름이 TimeSource TimeMark 로 변경

* ArrayDeque 추가

* Collection builders

  * collections의 builder 함수, builderList, buildset, buildMap 추가, 결과는 read-only collection

* reduceOrNull(), randomOrNull() 추가(기존 reduce(), random()은 emptyCollection이면 exception)

* scan() 추가, fold 처럼 acculated

 

InteliJ Kotlin 플러그인 개선

* gradle.kts 지원

* 자동완성개선

* 신규 색상 스키마

* 디버깅 개선

 

 

출처

https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/

 

Version : 1.4.0, release : 20.08.17

IDE 성능 및 안정성 향상을 포함한 Kotlin의 전반적인 개발환경을 개선하는데 초점

* 코루틴 디버거 도입

* 새로운 컴파일러, 목표는 속도 개선, 모든 플랫폼을 통합하며 확장기능의 API 제공(1.5에서는 디폴트로..)

 

신규 기능

* 코틀린 인터페이스에 SAM(Single Abstract Method) 컨벤션

* 라이브러리 개발자를 위한 명시적 API(메소드 가시성 수정 등)

* 일반 파라미터, 네임드 파라미터 혼용 가능

* 후행 콤마(trailing comma)

* callable method ref(::callableMethod)

* loop 내에 when에서 라벨없이 break와 continue 사용가능

 

 

 

출처

https://blog.jetbrains.com/kotlin/2020/08/kotlin-1-4-released-with-a-focus-on-quality-and-performance/

 

 

Version : 1.4.10, release : 20.09.07

블로그 글이 안보이네요..^^;;

 

 

Version : 1.4.20, release : 20.11.23

 

JVM 신규 기능 지원(invokedynamic을 통한 String concatenation)(1.5에 기본값으로 변경 예정)

* JDK9 부터 String 을 합치는 부분은 dynamic method invocation(invokedynamic)을 통해 수행한다.

* 이전보다 더 빠르고 메모리를 적게 소모하며 바이트코드 변경없이 최적화 할수 있는 여지를 제공한다.

  * ex) 이전에는 StringBuilder로 하나한 연결 했던 바이트 코드를 생성했기 때문에 최적화할 여지가 더 없지만, ivokedynamic을 통해 bootstrap method를 호출하는 형태의 바이트코드로 생성되고 bootstrap method는 호출되는 시점에 생성되기 때문에 최적할 여지가 생김(Bootstap에 호출은 보통 StringConcatFactory.makeConcatWithConstrants를 호출한다고 함

* invokedynamic : https://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html#invokedynamic

  * https://openjdk.java.net/jeps/280

  * https://www.baeldung.com/java-string-concatenation-invoke-dynamic

 

성능 개선 및 KMM프로젝트에 대한 에러 핸들링

* 주로 Kotline/Native

* String.replace 성능 개선

JDK Path

 

출처

https://blog.jetbrains.com/kotlin/2020/11/kotlin-1-4-20-released/

 

Version : 1.4.30, release : 21.02.04

1.4.x에 마지막 릴리즈

1.5.0에 계획된 많은 실험적인 기능들 추가

 

언어 기능 및 컴파일러

* new JVM backend BETA

  * JVM backend : 코틀린 코드를 JVM에 동작하기 위한 바이트 코드로 생성하는데 활용되는 백엔드

* Value class, JVM records, sealed interface

  * Inline classes(Value class) : 인라인 클래스는 별도의 언어 기능이였지만, 현재는 하나의 매개변수가 있는 Value 클래스에 대해 JVM 최적화가 되었음, Value 클래스보다는 일반적인 개념이며 추후 다양한 최적화를 지원함.

  * JVM record : JDK14에 공개된 record에 대한지원, kotline의 data class와 유사

    * https://openjdk.java.net/jeps/395

  * sealed interface : 해당 인터페이스를 구현하거나 상속받은 클래스 혹은 인터페이스는 동일한 컴파일 단위 및 동일한 패키지에 있어야함, 그전에는 같은 파일에 존재했어야 했으나, 1.5에서는 다른파일에도 존재가능

    * JDK15에 도입되었으며 Kotlin 에서 JVM17이상 사용하는 경우에는 JVM에 있는 sealed class를 사용되도록 할것임

빌드 툴

  * 코틀린 gradle 플러그인에 캐시지원 설정

    * 주로 안드로이드 처럼 빌드가 오래걸리는 케이스에 대한...

 

 

출처

https://blog.jetbrains.com/kotlin/2021/02/kotlin-1-4-30-released/

 

Version : 1.5.0, release : 21.05.05

1.4.30에 도입되었던 신규 기능의 stable 버전

* JVMRecord 지원

  * data 클래스에 @JvmRecord 어노테이션 사용시 JVM에 record를 활용하도록 됨

* sealed class

  * 이전에는 모든 상속받은 클래스는 같은패키지 같은 파일내에 있어야 했지만, 현재는 다른 파일에서도 가능

* value class,  1개의 필드를 가진 value holder 클래스 이며 메모리 할당 오버헤드 없이 사용할수 있도록 함, 단, @JvmInline을 반드시 써줘야함

 

Kotlin/JVM

* 신규 JVM IR(Intermediate Representation) compiler 도입

* 람다를 invokedynamic로 컴파일(실험 기능)

* 디폴트 JVM은 1.8, 1.6은 사용중단* 

 

 

 

출처

https://blog.jetbrains.com/kotlin/2021/05/kotlin-1-5-0-released/

댓글()

[Kotlin] default argument, named argument

Kotlin|2019. 9. 18. 20:10

코틀린이 편리한 부분이 많다는것들은 많이 봤지만

("var ${var}" 도 그렇고.. data class도 그렇고 null check도 그렇고 너무 많네요..;;)

 

몰랐던 기능이 있어 기록을 남깁니다.

 

먼저 "default argument"

 

자바에서 보통 인자가 없을때 그리고 인자가 있을때 처리를 위해

메소드 오버로딩으로 처리하곤 합니다

 

이코드가 결국에는 default 값 처리를 위한 건데

결국 arg가 없는 메소드를 열어봐야 기본값을 알 수 있습니다.

public void hello(){
	hello("kim");
}

public void hello(String name){
	System.out.println("Hello " + name);
}


/////////아니면 아래처럼 null로 넘기고 null이면 기본값 처리하는 방법이..

public void hello(){
	hello(null);
}

public void hello(String name){
	String localName = name;
	if(localName==null){
		localName="kim";
	}
	System.out.println("Hello " + localName);
}

 

그런데 코틀린에서는 아래와 같이 코드를 작성해서 default argument를 설정할 수 있습니다.

fun hello(name: String="kim")=println("hello ${name}")

훨씬 간결해집니다.

 

그럼 인자가 많아지거나 다양해지면 어떻게 하나?

(몇개는 입력을 받고 몇개는 default로 처리하고 싶을때... )

 

자바로 작성하면 null체크를 덕지덕지 처리를 해주기도하고

overload 메소드를 거의 종류별로 만들어야 하는 경우도 생기기 때문에

args가 늘어나는것 대신 보통 input용 클래스를 빌더패턴으로 만들던 그냥 data 클래스로 만들던 만들어서 코드를 처리하기도 합니다.

 


	public void order() {
		order(null, -1);
	}

	public void order(int cnt) {
		order(null, cnt);
	}

	public void order(String menuName) {
		order(menuName, -1);
	}

	public void order(String menuName, int cnt) {
		String localName = menuName;
		if (localName == null) {
			localName = "대표메뉴";//default Menu
		}
		int localCnt = cnt;
		if (localCnt == -1) {
			localCnt = 1;// default Cnt
		}
		System.out.println(menuName + " order " + cnt);
	}

 

코틀린에서는 "named argument"를 써서 쉽게 처리할 수 있습니다.

 

fun order(menuName: String="대표메뉴", cnt: Int=1)=println("${menuName} order ${cnt}")

여기까지는 위에 default argument와 동일합니다.

여기서 중요한건 사용할때 기존 order(null,10) 형태로 호출하는것이 아니라

아래와 같이 인자를 줄때 변수을 명시해서 넘길수 있습니다.

		order("피자", 5)//결과적으로 "피자 order 5", 모두 채운 기존 형태
		order(3)//에러
		order("피자")//결과적으로 "피자 order 1"
		order(menuName = "피자")//결과적으로 "피자 order 1"
		order(cnt = 3)//결과적으로 "대표메뉴 order 3"
		order(menuName = "피자", cnt = 5)//결과적으로 "피자 order 5"
        order(cnt = 5, menuName = "피자")//결과적으로 "피자 order 5", 순서 상관없이 잘 동작합니다
		

 

named argument 덕분에 첫번째 인자가 어떤 변수인지 두번째 인자가 어떤 arg인지

메소드 선언을 보지 않아도 호출하는 쪽에서 변수명을 명시하면 혼동을 덜할수 있고

arg순서가 바뀌거나(물론 유지보수를 위해 메소드 arg를 막 변경하는 사람은 없겠지만) arg가 늘어나는 경우에도

대응하기 좋을것으로 보입니다.

 

 

 

댓글()

[Kotlin] 코틀린에 primitive가 없다고? 느리지 않을까?

Kotlin|2019. 9. 10. 19:47

자바에는 primitive 타입과 Object 타입이 동시에 있는 것들이 있다는 것은

자바 개발자라면 대부분 다들 알고 있을 겁니다.

(int와 Integer , long와 Long, 등등....)

 

primitive 타입과 Object 타입이 각각 존재하는 것은 

여러 가지 이유가 있지만, 제가 생각하는 가장 큰 이유는

연산을 할 때마다 새로운 객체를 만들기 위해 메모리 할당을 한다면 성능상 문제가 생길 수 있기 때문에

(보통 Object + Object는 새로운 Object를 생성... 숫자 연산마다 메모리 할당이 생긴 하다.. 문제가 되겠죠)

출처 : https://www.scientecheasy.com/2018/06/memory-allocation-primitive-nonprimitive.html

primitive type을 두어 primitive는 heap에 할당하지 않고 스택에 value를 바로 value를 저장하여 성능 향상한 것으로 알고 있습니다.

 

primitive를 통해 성능 향상한 것은 좋지만, java Collection을 통해 int를 담거나 제네릭으로 타입을 처리하거나

할 때 primitive로는 처리가 불가능하기 때문에

primitive를 wrapping 타입(Integer)으로 변경해야 하는 경우가 필요하곤 합니다.

 

물론, java에서 자동으로 primitive에서 wrapping 타입 변환(auto-boxing) wrapping에서 primitive(auto-un-boxing)을 해주기도 하지만, 편리할 뿐 boxing 때마다 object가 생기고 사라지기 때문에 그리 성능상 좋지는 않고 불편하기도 합니다.

(NPE 문제.. 타입 처리 문제...)

 

불편하기도 하지만 성능 때문이라도 계속 primitive 타입이 존재하죠..

그래서, 많은 연산 시에는 wrapping 타입 대신 primitive 타입을 사용하라곤 합니다.

 

int[] values = {...};

int sum=0;
for(val : values){
	sum+=val;
}


Integer sum=0;//이렇게 하지 말라곤 하죠
for(val : values){
	sum+=val;//이렇게 하지 말라곤 하죠
}

 

 

그런데!

코틀린은 이 불편한 primitive가 없다고 합니다.

(실제로 코틀린은 int 대신 Int, double 대신 Double)

없어져서 좋을 수 있지만, "그럼 코틀린은 wrapping 타입만 사용한다는 걸까? 그럼 느리지 않을까?"

라는 의문이 생겼습니다.

 

그럼 위에서 언급한 연산 때마다 객체가 생기고 사라지고를 반복해서 문제가 생기지 않을까요?

 

그래서 테스트해봤습니다.

 

테스트 방법은

  • 1. 테스트 코드 작성
  • 2. class 파일 생성
  • 3. 디컴파일러로 class 파일 확인

을 통해 어떻게 class 파일이 생성되는지 확인하려고 합니다.

 

 

1. 자바

먼저, 자바로 primitive일 때

 

	int number_1 = 100;
		number_1 += 10;

	int number_2 = 200;
		number_2 += 10;

	int sum = number_1 + number_2;
		System.out.println(String.format("sum : %d", sum));

 

하단은 디컴파일러를 통해 본 자바 primitive 코드

 

거의 차이가 없습니다. 다만 마지막 라인에 String.format()에

마지막 arg는 Object []이기 때문에 Integer.valueOf()로 오토 박싱 한 부분이 보입니다.

 

지금까지 객체는 마지막 한 번만 객체 생성이 되겠네요

(물론 정확하게는 Integer.valueOf()가 내부적으로 범위 값만큼은 객체를 캐싱을 하고 있기 때문에 객체를 만들지 않겠지만요..)

 

두 번째로, 박싱 타입인 Integer로 위 코드를 사용하면 어떻게 코드가 생성되는가?

	Integer number_1 = 100;
		number_1 += 10;

	Integer number_2 = 200;
		number_2 += 10;

	Integer sum = number_1 + number_2;
		System.out.println(String.format("sum : %d", sum));

 

하단은 디컴파일러를 통해 본 자바 Integer 코드

 

 

 

100이라고 적은 int는 number_1이 Integer 타입이기 때문에 Integer.valueOf()로 오토 박싱 처리되었고

number_1 +=10 은 number_1이 Integer 타입이기 때문에 내부 primitive를 가져오는. intValue()를 사용해서 int인 10과 더하고

다시 박싱 하여 number_1에 assign 하는 식으로 동작하는 것을 볼 수 있습니다.

 

앞서 말한 것처럼 거의 연산 때마다 객체가 새로 생성되는 것을 볼 수 있습니다.

 

 

2. 코틀린

 

궁금해하던 코틀린입니다.

타입을 명시하지 않고 해 봤습니다.

(:Int로 명시해도 디컴파일 결과는 같았습니다.)

	var number_1 = 100;
		number_1 += 10;


	var number_2 = 200;
		number_2 += 10;

	var sum = number_1 + number_2;
		println("sum : ${sum}")

 

하단은 디컴파일러를 통해 본 코틀린 코드

 

 

디컴파일 했더니 박싱 타입인 Integer를 사용하지 않고 primitive 인 int로 생성되는 것을 볼 수 있었습니다.

Integer가 아닌 int로 변환한 걸 봐서는 우려했던 부분에 성능 문제는 발생하지 않겠네요

다만, println("sum : ${sum}")에 문자열 조합을

+연산을 통해 처리하고 부분이 조금 마음에 걸리네요(물론 variable이 하나라 +를 쓴 건지 나중에 확인해봐야겠네요)

 

 

마지막으로 하나 더 테스트해봤습니다.

:Int를 primitive로 처리하고 있는 건 알겠는데

"그럼 Collection에서는 primitive int로 어떻게 처리하려나?"였습니다.

 

var list = arrayListOf<Int>();

(1..10).forEach { n -> list.add(n) }

list.forEach { n -> println(n) }

 

하단은 디컴파일러를 통해 본 코틀린 코드, 실제 코드는 3줄이나, 코드는 정말 길게 만들어지네요..

 

....

 

여기서 사실 살펴볼 쪽은 색칠해둔 부분인데 너무 작아 보이지 않으실 테니

적자면

list.add(Integer.valueOf(n))

으로 처리를 하고 있습니다.

결국에는 ArrayList를 사용하기 위해 자바와 동일하게 오토 박싱을 하고 있긴 하네요

 

 

 

결론

코틀린에는 primitiveType은 없지만, 바이트코드로 변환 시 가능한 한 primitiveType으로 바꿔주어

연산 시 성능 문제는 발생하지 않을 것으로 보이며

Collection은 마찬가지로 autoBoxing 처리를 하고 있다.

 

 

나중에 자바에서는 String append시 StringBuilder나 Buffer를 사용하도록 하는데

코틀린에서는 어떻게 처리하고 있나 봐야겠습니다.

 

'Kotlin' 카테고리의 다른 글

split과 동시에 assign  (0) 2021.11.29
코틀린 upgrade 1.3.7 to 1.5.0  (0) 2021.05.28
[Kotlin] default argument, named argument  (0) 2019.09.18
[Kotlin] data class  (0) 2019.09.09
[Spring][Kotlin] 필드에 @Autowired 어떻게 사용하나?  (0) 2019.09.06

댓글()

[Kotlin] data class

Kotlin|2019. 9. 9. 18:10

자바에서는 모델 혹은 DTO 혹은 Entity 클래스들을 만들때 

툴에 getter setter 을 자동으로 만들어주는 기능이나 롬복을 활용하여

해당 노가다를 줄이곤 했습니다.

 

코틀린에서는 data class가 존재하여 해당 부분에 코드를 간편히 생성할수 있도록 제공하고 있었습니다.

 

일단 data 클래스에서 제공하는 것은 

 

1. 모든 필드 기반 hashCode & equals 자동 구현

2. 모든 필드 기반 toString 자동구현

3. getter 대신 compoentN() // N은 필드순, 1 부터

4. copy(필드들), (args를 해당 객체를 받지 않고 필드들을 받아서 거의 생성자느낌에 구현이..)

 

들을 지원합니다.

 

Emp 클래스에 empno와 ename 이 있다고 했을때

자바로 Emp 클래스를 만들면

public class Emp {
	private Integer empno;
	private String ename;
	public Integer getEmpno() {
		return empno;
	}
	public void setEmpno(Integer empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((empno == null) ? 0 : empno.hashCode());
		result = prime * result + ((ename == null) ? 0 : ename.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Emp other = (Emp) obj;
		if (empno == null) {
			if (other.empno != null)
				return false;
		} else if (!empno.equals(other.empno))
			return false;
		if (ename == null) {
			if (other.ename != null)
				return false;
		} else if (!ename.equals(other.ename))
			return false;
		return true;
	}
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Emp [empno=").append(empno).append(", ename=").append(ename).append("]");
		return builder.toString();
	}

}

이렇게 장황한 코드가

 

코틀린으로는

data class Emp(
	var empno: Int?,
	var ename: String
) {
	constructor() : this(null,"")
}

 

이렇게 간단한 코드가 됩니다.

 

개발시 모델 변경이 자주 발생한다면 더더욱 큰 차이라고 볼수 있고

 

"나는 모델 변경이 거의 없는데?" 라고 하더라도

이슈로 모델코드를 자바코드를 봤을때 절대적으로 라인 코드가 길기 때문에

혹시 잘못 구현한 hashCode()나 null처리 등 체크하는것만으로도 낭비 시간들이 발생할수 있을것으로 생각됩니다.

(물론 자바를 사용하더라도 롬복을 쓰면 차이가 없지만요^^;;)

 

댓글()

[Spring][Kotlin] 필드에 @Autowired 어떻게 사용하나?

Kotlin|2019. 9. 6. 19:02

아직 익숙하지 않지만, 코틀린을 조금씩 학습중에 @Autowired를 어떻게 써야하는지 난감한 상황이 생겼습니다.

 

자바에서는 일반적으로 

 

@Autowired
private EmpDao empDao;

형태로 간단히 사용할수 있지만

 

코틀린에서

 

@Autowired
var empDao: EmpDao;

'Property must be initialized or be abstract' 에러와 함께 동작하지 않았습니다.

 

그럴때는'lateinit' 을 사용하면 에러 없이 사용가능합니다.

@Autowire
lateinit var empDao : EmpDao;

 

참고 : https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties

'Kotlin' 카테고리의 다른 글

split과 동시에 assign  (0) 2021.11.29
코틀린 upgrade 1.3.7 to 1.5.0  (0) 2021.05.28
[Kotlin] default argument, named argument  (0) 2019.09.18
[Kotlin] 코틀린에 primitive가 없다고? 느리지 않을까?  (1) 2019.09.10
[Kotlin] data class  (0) 2019.09.09

댓글()