오랜만에 leetCode easy 단계를 푸는 도중에 stream에 관련한(stream인지 .toArray인지 모르겠군요.) 재밌있는 사실(
저만 몰랐겠죠..?)을 발견했습니다.이에 관해 글을 작성해 보겠습니다.
문제
class Solution { public void static main(String[args){ int nums[] = new int[]{3,2,2,3}; int val = 3; removeElement(nums, val); ... // nums 검사 for (int i = 0; i < expectedNums[i].length; i++) { assert nums[i] == expectedNums[i]; } } // logic 구현 public int removeElement(int[] nums, int val) { ... } }
위의 코드와 같이 int[]
인 nums를 메서드 실행 이후에 재검사하는 로직을 작성하는 문제입니다.
처움 제가 푼 로직은 아래와 같습니다.
public int removeElement(int[] nums, int val) { nums = Arrays.stream(nums).filter(num -> num != val).toArray(); return nums.length; }
이 후 Run Code 를 해보니 기존에 있는 nums의 값이 변경되지 않더군요.
그래서 결국 아래의 방법으로 문제를 해결했습니다.(해당 페이지의 Solution 탭에 존재합니다.)
public int removeElement(int[] nums, int val) { // nums = Arrays.stream(nums).filter(num -> num != val).toArray(); // return nums.length; int i = 0; for (int j = 0; j < nums.length; j++) { if (nums[j] != val) { nums[i] = nums[j]; i++; } } return i; } }
이 해결방법과 위의 stream을 사용한 방법의 차이점에 대해 궁금증이 들더군요.
그래서 실행 전과 실행 후의 reference를 비교하는 몇가지 test를 진행해 보았습니다.
Stream을 활용한 방법
Code
class Solution { public static void main(String[] args) { int nums[] = new int[]{3,2,2,3}; int val = 3; // method 호출 전 original nums의 reference 출력 System.out.println("Nums = " + nums+" Original"); RemoveElement.removeElement(nums, val); // method 호출 후 original nums의 reference 출력 System.out.println("Nums = " + nums+" After Original"); } public static int removeElement(int[] nums, int val) { // method 내의 처리 '전' parameter로 받은 nums의 reference 출력 System.out.println("nums = " + nums+" InMethod1"); nums = Arrays.stream(nums).filter(num -> num != val).toArray(); // method 내의 처리 '후' parameter로 받은 nums의 reference 출력 // 이 부분의 reference가 다름! System.out.println("nums = " + nums+" InMethod2"); return nums.length; }
Result
보시는바와 같이 처리된 nums 의 reference만 다른 것을 알 수 있습니다.
forLoop 방법(index에 값 직접 입력)
class Solution { public static void main(String[] args) { int nums[] = new int[]{3,2,2,3}; int val = 3; // method 호출 전 original nums의 reference 출력 System.out.println("Nums = " + nums+" Original"); RemoveElement.removeElement(nums, val); // method 호출 후 original nums의 reference 출력 System.out.println("Nums = " + nums+" After Original"); } public static int removeElement(int[] nums, int val) { // method 내의 처리 '전' parameter로 받은 nums의 reference 출력 System.out.println("nums = " + nums+" InMethod1"); int i = 0; for (int j = 0; j < nums.length; j++) { if (nums[j] != val) { nums[i] = nums[j]; i++; } } // method 내의 처리 '후' parameter로 받은 nums의 reference 출력 // 이 부분의 reference가 다름! System.out.println("nums = " + nums+" InMethod2"); return nums.length; }
result
이렇게 forLoop
을 사용하여 nums 배열의 index에 직접적으로 값을 입력 할 시 해당 reference가 변경되는 것을 알 수 있습니다.
java8 documentation
java8의 stream.toArray의 doc을 확인 해 보았습니다.
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#toArray--
Parameters 부분의 generator에서 a new Array를 생성한다고 나와 있군요.
...?
생각해보니 기존의 배열에 다른 배열을 할당하는 순간 reference가 변경되었던것 같은데....? 라는 의문이 들더군요!
public static void test(int[] n){ System.out.println("n = " + n); int[]m = {1,2,3}; n = m.clone(); System.out.println("n = " + n); }
네... 그렇네요ㅎㅎ
java의 reference에 대한 정확한 이해가 부족해서 발생한 문제였습니다 ㅠㅠ
reference가 변하지 않게 값을 수정해 주려면 reference를 가리키고 있는 값을 직접 바꿔야 한다는 것을 망각했었네요.
아직도 배울것들, 기억해야 할 것들이 많이 남아 있네요.
긴 글 읽느라 고생하셨습니다~ 모두 즐거운 프로그래밍 하시길 바랍니다~
'Languages > java' 카테고리의 다른 글
[Java] Exception(checked, Unchecked Exception) (0) | 2022.06.16 |
---|---|
[java]상속보다는 컴포지션을 사용하기 (0) | 2022.05.09 |
JitPack을 활용하여 라이브러리 생성하기(maven, gradle) (0) | 2022.01.30 |
[VSCode] 환경설정하기 (0) | 2021.07.30 |
2021_07_13)[java] Static이란? (0) | 2021.07.13 |