<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>예스30</title>
    <link>https://soozl91.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 10 Apr 2026 04:21:59 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>키키수수</managingEditor>
    <image>
      <title>예스30</title>
      <url>https://tistory1.daumcdn.net/tistory/3003705/attach/69892eaae6b8430b878000a57038eebf</url>
      <link>https://soozl91.tistory.com</link>
    </image>
    <item>
      <title>[JAVA] Stream 중간연산</title>
      <link>https://soozl91.tistory.com/76</link>
      <description>&lt;h1&gt;중간연산&lt;/h1&gt;
&lt;p&gt;스트림은 마치 데이터베이스에 질의를 하는 것과 같은 느낌, 중간 연산과 최종 연산으로 분류할 수 있으며 중간 연산은 연속해서 연결할 수 있다. 반면 최종 연산은 한번만 가능하다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;지연된 연산&lt;/strong&gt;, 최종 연산이 수행되기 전까지 중간 연산은 수행되지 않는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;code&gt;skip(), limit()&lt;/code&gt; 자르기&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;class StreamTest {

    @Test
    public void 자르기() {
        // 1 ~ 9 까지 배열 생성
        int[] one2nine = IntStream.range(1, 10).toArray();
        assertThat(one2nine).isEqualTo(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9});

        // 3번째 요소까지 스킵, 그 후 두개만
        int[] four2five = Arrays.stream(one2nine)
                .skip(3)
                .limit(2)
                .toArray();
        assertThat(four2five).isEqualTo(new int[]{4, 5});

        // 소스에서 처음 5개만
        int[] one2five = Arrays.stream(one2nine).limit(5).toArray();
        assertThat(one2five).isEqualTo(new int[]{1, 2, 3, 4, 5});
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;filter(), distinct()&lt;/code&gt; 거르기&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;class StreamTest {
    @Test
    public void 거르기() {
        int[] numbers = new int[]{1, 1, 2, 2, 4, 5, 5, 7, 9};

        // 짝수만
        // Stream&amp;lt;T&amp;gt; filter(Predicate&amp;lt;T&amp;gt; predicate);
        int[] evenNumbers = Arrays.stream(numbers)
                .filter(v -&amp;gt; v % 2 == 0)
                .toArray();
        assertThat(evenNumbers).isEqualTo(new int[]{2, 2, 4});

        // 중복제거
        // Stream&amp;lt;T&amp;gt; distinct()
        int[] distinctNumbers = Arrays.stream(numbers)
                .distinct()
                .toArray();
        assertThat(distinctNumbers).isEqualTo(new int[]{1, 2, 4, 5, 7, 9});
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;sorted()&lt;/code&gt; 정렬&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Stream&amp;lt;T&amp;gt; sorted();
Stream&amp;lt;T&amp;gt; sorted(Comparator&amp;lt;? super T&amp;gt;comparator);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Comparator 대신 int값을 반환하는 람다식을 사용하는 것도 가능함, 파라미터가 없는 매서드는 스트림을 기본정렬한다. 단, 스트림의 요소가 Comparable을 구현하지 않았다면 예외가 발생한다.&lt;/p&gt;
&lt;p&gt;Comparator는 많은 API가 있지만 가장 기본적인 메서드는 아래와 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;comparing(Function&amp;lt;T, U&amp;gt; keyExtractor);
comparing(Function&amp;lt;T, U&amp;gt; keyExtractor,Comparator&amp;lt;U&amp;gt; keyComparator);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;스트림의 요소가 comparable을 구현했을 경우 파라미터가 한개인 메서드를 사용하고, 그렇지 않은경우는 Comparator를 지정한다. 기본형의 경우 comparing() 대신 comparing기본형()을&lt;br&gt;사용한다. 정렬 조건을 추가할 때는 thenComparing()을 사용한다.&lt;/p&gt;
&lt;p&gt;학생스트림을 학년순, 반순, 성적으로 정렬하는 방법은 아래와 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Arrays.stream(stuArr).sorted(Comparator.&amp;lt;Student&amp;gt;comparingInt(v-&amp;gt;v.getHak())
                .thenComparingInt(v-&amp;gt;v.getBan())
                .thenComparingInt(v-&amp;gt;v.getScore())
).forEach(System.out::println);&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;map()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;스트림의 요소에서 원하는 값만 뽑아내거나 특정 형태로 변환해야 할때 사용한다. mapToInt, mapToDouble, mapToLong등 기본형 스트림으로 변환하는&lt;br&gt;메서드도 있다.&lt;/p&gt;
&lt;p&gt;mapToInt의 경우 IntStream이 반환되는데 count()만 지원하던 Stream과 달리 기본형스트림은 숫자를 다루는데 편리한 메서드들을 제공한다.&lt;br&gt;아래의 메서드는 최종연산으로 호출 후에는 스트림이 닫힌다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;sum()
average()
max()
min()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 네가지 결과를 얻으려면 스트림을 네번 생성해야되는데 그 귀찮음을 방지한 summaryStatistics() 라는 메서드가 제공된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Test
public void 써머리(){
  IntSummaryStatistics scoreStat = Arrays.stream(stuArr).mapToInt(v -&amp;gt; v.getScore()).summaryStatistics();

  log.info(String.valueOf(scoreStat.getSum()));
  log.info(String.valueOf(scoreStat.getMax()));
  log.info(String.valueOf(scoreStat.getMin()));
  log.info(String.valueOf(scoreStat.getAverage()));
  log.info(String.valueOf(scoreStat.getCount()));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;peek()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;연산과 연산 사이에 올바르게 처리되었는지 확인하고 싶을때 사용한다. foreach와 달리 스트림의 요소를 소모하지 않기때문에&lt;br&gt;중간연산들 사이에 넣어도 문제가 되지 않는다.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;flatMap()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;스트림의 요소가 배열이거나, map의 연산결과가 배열&lt;/strong&gt;일 경우, 즉 스트림의 타입이 Stream&amp;lt;T[]&amp;gt;의 경우 Stream&lt;T&gt;로 다룰 수 있도록 한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;스트림의 요소가 배열일때, map의 연산결과가 배열일때&lt;/li&gt;
&lt;li&gt;그 배열에서 모든 요소를 꺼내 하나의 스트림으로 감쌀때&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Stream&amp;lt;String[]&amp;gt; -&amp;gt; Stream&amp;lt;String&amp;gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Main/Java</category>
      <category>DISTINCT</category>
      <category>Filter</category>
      <category>foreach</category>
      <category>LIMIT</category>
      <category>map</category>
      <category>peek</category>
      <category>skip</category>
      <category>STREAM</category>
      <category>스트림</category>
      <category>스트림중간연산</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/76</guid>
      <comments>https://soozl91.tistory.com/76#entry76comment</comments>
      <pubDate>Tue, 30 Mar 2021 11:56:58 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA] Stream</title>
      <link>https://soozl91.tistory.com/75</link>
      <description>&lt;h1&gt;스트림&lt;/h1&gt;
&lt;p&gt;데이터 소스가 무엇이던 간에 같은 방식으로 다룰 수 있게 추상화 함, 즉 배열이나 컬렉션뿐만 아니라 파일도 모두 같은 방식으로 다룰 수 있음&lt;/p&gt;
&lt;h2&gt;특징&lt;/h2&gt;
&lt;h3&gt;1. 데이터 소스를 변경하지 않음&lt;/h3&gt;
&lt;p&gt;데이터를 읽기만 할 뿐 데이터 소스를 변경하지 않음&lt;/p&gt;
&lt;h3&gt;2. 일회용&lt;/h3&gt;
&lt;p&gt;한번 사용하면 닫혀서 다시 사용할 수 없음&lt;/p&gt;
&lt;h3&gt;3. 내부 반복으로 처리&lt;/h3&gt;
&lt;p&gt;스트림으로 작성한 코드가 간결할 수 있는 이유는 내부반복&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;class Stream {
    void forEach(Consumer&amp;lt;? super T&amp;gt; action) {
        Objects.requireNonNull(action);
        for (T t : src) {
            action.accept(t);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 연산&lt;/h3&gt;
&lt;p&gt;스트림은 마치 데이터베이스에 질의를 하는 것과 같은 느낌, 중간 연산과 최종 연산으로 분류할 수 있으며&lt;br&gt;중간 연산은 연속해서 연결할 수 있다. 반면 최종 연산은 한번만 가능하다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;지연된 연산&lt;/strong&gt;, 최종 연산이 수행되기 전까지 중간 연산은 수행되지 않는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;생성&lt;/h2&gt;
&lt;h3&gt;컬랙션&lt;/h3&gt;
&lt;p&gt;컬랙션의 최고 조상인 Collection에 stream()이 정의 되어 있음, 그러므로 list, set의 구현체들은 모두 스트림을 생성할 수 있음&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;List&amp;lt;String&amp;gt; stringList = new ArrayList&amp;lt;&amp;gt;(Arrays.asList(&amp;quot;김&amp;quot;,&amp;quot;은&amp;quot;, &amp;quot;수&amp;quot;, &amp;quot;김&amp;quot;));
Stream&amp;lt;String&amp;gt; listStream = stringList.stream();
listStream.forEach(System.out::println);

System.out.println();

Set&amp;lt;String&amp;gt; stringSet = new HashSet&amp;lt;&amp;gt;(Arrays.asList(&amp;quot;김&amp;quot;,&amp;quot;은&amp;quot;, &amp;quot;수&amp;quot;, &amp;quot;김&amp;quot;));
Stream&amp;lt;String&amp;gt; setStream = stringSet.stream();
setStream.forEach(System.out::println);&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;배열&lt;/h3&gt;
&lt;p&gt;Stream과 Arrays에 정의되어 있음&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Stream.of(T... values);
Stream.of(T[] t);
Arrays.stream(T[] t);
Arrays.stream(T[] t, int startIncluesive, int endExcluesive);
IntStream.of(int... values);
IntStream.of(int []);&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;특정 범위의 정수&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;IntStream.range(begin, end)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Intsream.rangeClosed(begin, end)&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;임의의 수&lt;/h3&gt;
&lt;p&gt;크기가 정해지지 않은 무한스트림이 생성되며 limit() 메서드를 사용해 제한해야함&lt;/p&gt;
&lt;p&gt;&lt;code&gt;IntStream randomIntStream = new Random().ints()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;LongStream randomLongStream = new Random().longs()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;IntStream randomIntStream = new Random().ints(5)&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;각 요소를 계산하여 스트림 생성&lt;/h3&gt;
&lt;p&gt;람다식에 의해 계산되는 값들을 무한스트림을 생성한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;첫번째 파라미터로 지정한 값부터 시작하여 f 함수로 의해 계산된 결과를 다시 seed 값으로 설정하고 계산을 반복하며 생성한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Stream&amp;lt;T&amp;gt; iterate(T seed, UnaryOperator&amp;lt;T&amp;gt; f)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;파라미터가 없는 람다식을 이용해 계산되는 값을 이용하여 생성한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Stream&amp;lt;T&amp;gt; generate(Supplier&amp;lt;T&amp;gt; s)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;파일&lt;/h3&gt;
&lt;p&gt;java.nio.file.Files는 파일을 다루는데 유용한 메서드들을 제공, list()는 지정된 디렉토리에 있는 파일의 목록을 소스로하는&lt;br&gt;스트림을 리턴함&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Stream&amp;lt;Path&amp;gt; pathStream =  Files.list(Path dir)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;파일 내용의 행을 요소로 하는 스트림&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Stream&amp;lt;String&amp;gt; contentStream = Files.lines(Path path)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Stream&amp;lt;String&amp;gt; contentStream = lines(); // BufferedReader클래스&lt;/code&gt;&lt;/p&gt;</description>
      <category>Main/Java</category>
      <category>STREAM</category>
      <category>스트림</category>
      <category>자바스트림</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/75</guid>
      <comments>https://soozl91.tistory.com/75#entry75comment</comments>
      <pubDate>Tue, 30 Mar 2021 11:55:30 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA] 람다식 기본</title>
      <link>https://soozl91.tistory.com/74</link>
      <description>&lt;h1&gt;Lambda Expression&lt;/h1&gt;
&lt;p&gt;JDK 1.8에 추가&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;메서드를 하나의 식(expression)으로 표현한것&lt;/li&gt;
&lt;li&gt;메서드를 람다식으로 표현하면 메서드의 &lt;strong&gt;이름&lt;/strong&gt; 이 없어지므로, 람다식을 &amp;#39;익명함수(anonymous function)&amp;#39;라고 함&lt;/li&gt;
&lt;li&gt;반환 타입이 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;메서드의 매개변수로 전달될 수 있고 메서드의 결과로 반환될 수 있으며 이로인해 메서드를 변수처럼 다루는 것이 가능해짐&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;메서드와 함수의 차이&lt;/p&gt;
&lt;p&gt;함수라는 이름은 수학에서 가져온 것이며 개념이 유사함.&lt;br&gt;객체지향의 개념에서는 함수 대신 객체의 행위나 동작을 의미하는 메서드라는 용어를 사용함&lt;/p&gt;
&lt;p&gt;메서드는 함수와 같은 의미지만 특정 클래스에 반드시 속해야 한다는 제약이있음&lt;br&gt;하지만 람다식은 메서드가 하나의 독립적인 기능을 하기 때문에 함수라는 용어가 사용됨&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;람다식 작성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;람다식에 선언된 매개변수의 타입은 추론이 가능한 경우는 생략할 수 있음, 반환타입이 없는 이유도 항상 추론이 가능하기 때문&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;익명함수답게 메서드에서 이름과 반환타입을 제거, 선언부와 몸통사이에 -&amp;gt;를 추가&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;int sum(int a, int b){
  return a + b;
}
(int a, int b) -&amp;gt; {return a + b;}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;반환값이 있는 메서드의 경우, return문 대신 식으로 대신할 수 있음, 식의 연산결과가 자동적으로 반환값이됨. 이때 문장이 아닌 식이므로 끝에 ;를 붙이지 않음&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;(int a, int b) -&amp;gt; a + b
(int a, int b) -&amp;gt; {return a + b;}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;선언된 매개변수가 하나일 경우 괄호 생략가능, 단 매개변수의 타입을 선언했다면 괄호를 생략할 수 없음&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;a -&amp;gt; a * a
(int a) -&amp;gt; a * a&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;괄호 안의 문장이 하나일 때는 괄호를 생략할 수 있음, 문장의 끝에 ;을 붙이지 않으며 return 문일 경우 괄호는 생략할 수 없음&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;a, b -&amp;gt; a + b
a, b -&amp;gt; {return a + b;}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;함수형 인터페이스 (functional interface)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;람다식은 익명클래스의 객체와 동등하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public void 익명클래스(){

     AnonymousClass anonymousClass = new AnonymousClass() {
         @Override
         public void hello() {
             System.out.println(&amp;quot;hello Anonymous&amp;quot;);
         }
     };

     AnonymousClass lambda = () -&amp;gt; System.out.println(&amp;quot;hello anonymous&amp;quot;);

     anonymousClass.hello();
     lambda.hello();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;람다식으로 정의된 익명 객체의 메서드를 어떻게 호출 할 수 있을까? 참조변수가 있어야 객체의 메서드를 호출 할 수 있을탠데 람다식의 참조변수는 뭐라고 해야할까?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;타입 f = (a, b) -&amp;gt; a &amp;gt; b ? a : b;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;참조변수 f의 타입은 참조형이므로 클래스 또는 인터페이스가 가능함.&lt;/li&gt;
&lt;li&gt;람다식과 동등한 메서드가 정의되어 있어야 참조변수로 익명 객체(람다식)의 메서드를 호출할 수 있음&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;interface AnonymousClass {
 void hello();
}
@Test
void 익명클래스2() {
AnonymousClass anonymousClass = () -&amp;gt; System.out.println(&amp;quot;람다&amp;quot;);
anonymousClass.hello();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;매개변수의 타입, 개수, 반환값이 일치할 경우 대체가 가능&lt;/li&gt;
&lt;li&gt;함수형 인터페이스는 오직 하나의 추상 메서드만 정의되어 있어야함, 단 static 메서드와 default 메서드는 개수의 제한이 없음&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;@FunctionalInterface를 붙일 경우 컴파일러가 함수형 인터페이스를 올바르게 정의하였는지 확인해 줌 &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;외부 변수를 참조하는 람다식&lt;/h3&gt;
&lt;p&gt;람다식 내에서 참조하는 지역변수는 final이 붙지 않았어도 상수로 간주되며 람다식 내에서 참조하고 있는 지역 변수는&lt;br&gt;식 내에서나 다른 어느 곳에서도 변수의 값을 변경하는 일은 허용하지 않는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;    int classVariable = 5;

    @Test
    public void 람다식의지역변수참조() {
      int c = 1; // == final int c = 1;

      lambda.FunctionSum sum = (a, b) -&amp;gt; {
        a = a + 20;
        classVariable = 50;
        return a + b + classVariable + c;
      };

      log.info(&amp;quot;result :{}&amp;quot;, sum.sum(3, 5));
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;java.util.function 패키지&lt;/h3&gt;
&lt;p&gt;일반적으로 자주 쓰이는 형식의 메서드를 함수형 인터페이스로 미리 정의해 둠, 가능한 이 패키지의 인터페이스를 활용하라&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Runnable : void run()
파라미터와 리턴값 없음
Supplier&amp;lt;T&amp;gt; : T get()
리턴값만 있음
Consumer&amp;lt;T&amp;gt; : void accept(T t)
파라미터만 있음
Function&amp;lt;T, R&amp;gt; : R apply(T t)
파라미터와 리턴값 있음 
Predicate &amp;lt;T&amp;gt; : boolean test(T t)
파라미터와 리턴값이 있고 리턴타입은 boolean, 조건식을 람다로 표현할때 사용한다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;파라미터가 두개인 함수형 인터페이스&lt;/h4&gt;
&lt;p&gt;2개인 경우 함수인터페이스에 Bi가 붙음, 보통 파라미터 타입으로 T를 사용하므로 알파벳순 T, U, V, W가 파라미터의 타입으로 사용됨&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;BiConsumer&amp;lt;T, U&amp;gt; : accept(T t, U u)
BiPredicate&amp;lt;T, U&amp;gt; : test(T t, U u)
BiFunction&amp;lt;T, U, R&amp;gt; : R apply(T t, U u)
Supplier의 경우 파라미터가 없는 메서드를 갖고있고 리턴타입이 두개가 될순 없으므로 Bi는 존재하지 않음&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;리턴타입이 3개 이상 필요할경우 직접 선언하여 만들어야함&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;UnaryOperator&amp;lt;T&amp;gt; T apply(T t) : Function의 sub
BinaryOperator&amp;lt;T&amp;gt; T apply(T t, T t2) : BiFunction의 sub&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Main/Java</category>
      <category>Lambda</category>
      <category>lamdaExpression</category>
      <category>람다식</category>
      <category>인터페이스</category>
      <category>자바람다식</category>
      <category>함수형인터페이스</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/74</guid>
      <comments>https://soozl91.tistory.com/74#entry74comment</comments>
      <pubDate>Tue, 30 Mar 2021 11:54:09 +0900</pubDate>
    </item>
    <item>
      <title>[React] props와 state</title>
      <link>https://soozl91.tistory.com/73</link>
      <description>&lt;h1&gt;Props&lt;/h1&gt;
&lt;p&gt;properties를 줄인 표현으로 컴포넌트 속성을 설정할때 사용한다. 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정한다.&lt;/p&gt;
&lt;h2&gt;props 기본값 설정 방법&lt;/h2&gt;
&lt;p&gt;defaultProps를 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const MyComponent = props =&amp;gt; {
  return &amp;lt;div&amp;gt;안녕하세요, {props.name}입니다.&amp;lt;/div&amp;gt; 
}

MyComponent.defaultProps = {
  name: &amp;#39;설정하지 않은 이름&amp;#39;
}

&amp;lt;MyComponent/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;propTypes를 통한 props검증&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/typechecking-with-proptypes.html&quot;&gt;참고&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;필수 props를 지정하거나 props의 타입을 지정할떄는 propTypes를 사용한다. defaultProps를 설정하는 방법과 유사하다.&lt;/p&gt;
&lt;p&gt;prop에 유효하지 않은 값이 전달 되었을 때, 경고문이 JavaScript 콘솔을 통해 보인다. propTypes는 성능상의 이유로 개발 모드(Development mode) 에서만 확인된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import PropTypes from &amp;#39;prop-types&amp;#39;;

class Greeting extends React.Component {
  render() {
    return (
      &amp;lt;h1&amp;gt;Hello, {this.props.name}&amp;lt;/h1&amp;gt;
    );
  }
}

Greeting.propTypes = {
  name: PropTypes.string
};&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;태그 사이의 내용을 보여주는 children&lt;/h2&gt;
&lt;p&gt;컴포넌트 태그 사이의 작성한 문자열을 컴포넌트 내부에서 사용하고 싶을 경우 children을 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const MyComponent = props =&amp;gt; {
  return &amp;lt;div&amp;gt;안녕하세요, {props.name} {props.children}&amp;lt;/div&amp;gt; 
}

&amp;lt;MyComponent name=&amp;#39;김은수&amp;#39;&amp;gt;입니다.&amp;lt;/MyComponent&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;클래스형 컴포넌트에서 props 사용하기&lt;/h2&gt;
&lt;p&gt;this.props로 참조한다. defaultProps, propsTypes 모두 동일한 방법으로 사용 가능하다.&lt;/p&gt;
&lt;h2&gt;읽기 전용&lt;/h2&gt;
&lt;p&gt;함수 컴포넌트나 클래스 컴포넌트 모두 &lt;strong&gt;props를 수정해선 안된다.&lt;/strong&gt; React는 유연하지만 한가지 엄격한 규칙이 있으며 모든 React Component는 자신의 props를 다룰 때 반드시 순수 함수처럼&lt;br&gt;동작해야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;//순수함수, 입력값을 바꾸혀 하지 않는다. 입력값이 동일하다면 동일한 결과를 반환한다.
function sum(a, b) {
  return a + b;
}

//순수함수가 아니다. 입력값을 변경한다.
function withdraw(account, amount) {
  account.total -= amount;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h1&gt;State&lt;/h1&gt;
&lt;p&gt;State는 props와 유사하지만, 비공개이며 컴포넌트에 의해 완전히 제어된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;클래스형 컴포넌트가 지니고 있는 state&lt;/li&gt;
&lt;li&gt;함수형 컴포넌트에서 &lt;code&gt;useState()&lt;/code&gt; 라는 함수를 통해 사용하는 state&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () =&amp;gt; this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      &amp;lt;div&amp;gt;
        &amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;
        &amp;lt;h2&amp;gt;It is {this.state.date.toLocaleTimeString()}.&amp;lt;/h2&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
}

ReactDOM.render(
  &amp;lt;Clock/&amp;gt;,
  document.getElementById(&amp;#39;root&amp;#39;)
);&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Clock /&amp;gt;&lt;/code&gt; 컴포넌트가 &lt;code&gt;ReactDOM.render()&lt;/code&gt;로 전달되었을 때 &lt;code&gt;React&lt;/code&gt;는 &lt;code&gt;Clock&lt;/code&gt; 컴포넌트의 &lt;code&gt;constructor&lt;/code&gt;를 호출&lt;/li&gt;
&lt;li&gt;&lt;code&gt;constructor&lt;/code&gt; 생성자 내부에서 &lt;code&gt;Clock&lt;/code&gt;이 현재 시각이 포함된 객체로 &lt;code&gt;this.state&lt;/code&gt; 를 초기화&lt;/li&gt;
&lt;li&gt;React는 Clock 컴포넌트의 render() 메서드를 호출&lt;/li&gt;
&lt;li&gt;React는 화면에 표시되어야 할 내용을 알게 됨&lt;/li&gt;
&lt;li&gt;React는 Clock의 렌더링 출력값을 일치시키기 위해 DOM을 업데이트&lt;/li&gt;
&lt;li&gt;Clock 출력값이 DOM에 삽입되면, React는 componentDidMount() 생명주기 메서드를 호출&lt;/li&gt;
&lt;li&gt;componentDidMount() 내부에서 Clock 컴포넌트는 매초 컴포넌트의 tick() 메서드를 호출하기 위한 타이머를 설정하도록 브라우저에 요청&lt;/li&gt;
&lt;li&gt;매초 브라우저가 tick() 메서드를 호출&lt;/li&gt;
&lt;li&gt;tick() 내부에서는 setState()에 현재 시각을 포함하는 객체를 호출하면서 UI 업데이트를 진행&lt;/li&gt;
&lt;li&gt;setState() 호출 덕분에 React는 state가 변경된 것을 인지하고 화면에 표시될 내용을 알아내기 위해 render() 메서드를 다시 호출&lt;/li&gt;
&lt;li&gt;이 때 render() 메서드 안의 this.state.date가 달라지고 렌더링 출력값은 업데이트된 시각을 표현&lt;/li&gt;
&lt;li&gt;React는 이에 따라 DOM을 업데이트합니다.&lt;/li&gt;
&lt;li&gt;Clock 컴포넌트가 DOM으로부터 한 번이라도 삭제된 적이 있다면 React는 타이머를 멈추기 위해 componentWillUnmount() 생명주기 메서드를 호출.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;state 올바르게 사용하기&lt;/p&gt;
&lt;h2&gt;직접 state를 수정하지 않는다.&lt;/h2&gt;
&lt;p&gt;this.state를 지정 할 수 있는 유일한 공간은 constructor 하나다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// 이 코드는 컴포넌트를 리렌더링하지 않는다.
this.state.comment = &amp;#39;Hello&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;setState()를 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;this.setState({comment: &amp;#39;Hello&amp;#39;});&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;state 업데이트는 비동기적일 수 있다.&lt;/h2&gt;
&lt;p&gt;React는 성능을 위해 컴포넌트에 작성된 setState() 함수들을 단일 업데이트로 한번에 처리할 수 있다.&lt;br&gt;&lt;strong&gt;this.props, this.state가 비동기적으로 업데이트 될 수 있기 때문에 다음 state을 이용하는 작업에서 해당 값에 의존해서는 안된다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아래와 같은 코드는 실패할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;this.setState({
  counter: this.state.counter + this.props.increment,
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;객체보다는 함수를 인자로 사용하는 다른 형태의 setState() 함수를 사용하여 해결할 수 있다. 첫번째 파라미터는 이전 state, 두번쨰 파라미터는 업데이트가 적용된 시점의 props를 받는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;this.setState((state, props) =&amp;gt; ({
  counter: state.counter + props.increment
}));&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;state 업데이트는 병합된다.&lt;/h2&gt;
&lt;p&gt;별도의 setState() 호출을 사용해 독립적으로 업데이트할 수 있습니다. 이후에 state는 병합되어 업데이트 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

  componentDidMount() {
    fetchPosts().then(response =&amp;gt; {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response =&amp;gt; {
      this.setState({
        comments: response.comments
      });
    });
  }

  render({

&amp;lt;.../&amp;gt;
}

)
;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Top-down&lt;/h2&gt;
&lt;p&gt;“하향식(top-down)” 또는 “단방향식” 데이터 흐름이라고 한다. 모든 state는 &lt;strong&gt;항상 특정한 컴포넌트가 소유&lt;/strong&gt;하고 있으며 그 state로부터 파생된 UI 또는 데이터는 오직 트리구조에서 자신의 **&lt;br&gt;“아래”에 있는 컴포넌트에만 영향을 미친다.**&lt;/p&gt;</description>
      <category>독서/React</category>
      <category>defaultProps</category>
      <category>prop-types</category>
      <category>PROPS</category>
      <category>propTypes</category>
      <category>react</category>
      <category>setstate</category>
      <category>state</category>
      <category>this.props</category>
      <category>useState</category>
      <category>리엑트</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/73</guid>
      <comments>https://soozl91.tistory.com/73#entry73comment</comments>
      <pubDate>Mon, 22 Mar 2021 17:50:29 +0900</pubDate>
    </item>
    <item>
      <title>[React]Component란?</title>
      <link>https://soozl91.tistory.com/72</link>
      <description>&lt;h1&gt;Component&lt;/h1&gt;
&lt;p&gt;컴포넌트의 이름은 항상 대문자로 시작한다. React는 소문자로 시작하는 컴포넌트를 DOM 태그로 처리한다.&lt;br&gt;div 는 HTML 태그로 인식하고, Welcome은 컴포넌트로 인식하며 범위내에 Welcome 컴포넌트가 있어야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;Welcome/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;클래스형 컴포넌트&lt;/h2&gt;
&lt;p&gt;state 기능 및 라이프사이클 기능을 사용할 수 있고 임의 메서드를 정의할 수 있다. render() 함수가 필수다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;class Welcome extends React.Component {
  render() {
    return &amp;lt;h1&amp;gt;Hello, {this.props.name}&amp;lt;/h1&amp;gt;;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;함수형 컴포넌트&lt;/h2&gt;
&lt;p&gt;state와 라이프 사이클 API의 사용이 불가하지만, Hooks 기능으로 대체할 수 있게 됐다. 공식 매뉴얼에서는 컴포넌트 작성시&lt;br&gt;함수형 컴포넌트의 사용을 적극 권한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function Welcome(props) {
  return &amp;lt;h1&amp;gt;Hello, {props.name}&amp;lt;/h1&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;컴포넌트 랜더링&lt;/h2&gt;
&lt;p&gt;React 엘리먼트는 사용자 정의 컴포넌트로도 나타낼 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const element = &amp;lt;Welcome name=&amp;quot;Sara&amp;quot; /&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;React는 사용자 정의 컴포넌트를 발견하면 JSX &lt;strong&gt;어트리뷰트와 자식을 해당 컴포넌트에 단일 객체로 전달&lt;/strong&gt;한다.&lt;br&gt;이 객체를 &lt;code&gt;props&lt;/code&gt;라고 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function Welcome(props) {
  return &amp;lt;h1&amp;gt;Hello, {props.name}&amp;lt;/h1&amp;gt;;
}

const element = &amp;lt;Welcome name=&amp;quot;Sara&amp;quot; /&amp;gt;; // {props.name} === &amp;#39;Sara&amp;#39;

ReactDOM.render(
  element,
  document.getElementById(&amp;#39;root&amp;#39;)
);&lt;/code&gt;&lt;/pre&gt;</description>
      <category>독서/React</category>
      <category>component</category>
      <category>Properties</category>
      <category>PROPS</category>
      <category>react</category>
      <category>리엑트</category>
      <category>컴포넌트</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/72</guid>
      <comments>https://soozl91.tistory.com/72#entry72comment</comments>
      <pubDate>Mon, 22 Mar 2021 17:49:17 +0900</pubDate>
    </item>
    <item>
      <title>[React] Element란?</title>
      <link>https://soozl91.tistory.com/71</link>
      <description>&lt;h1&gt;Element&lt;/h1&gt;
&lt;p&gt;엘리먼트는 컴포넌트의 구성요소이며 React앱의 가장 작은 단위다. 엘리먼트는 화면에 표시할 내용을 기술한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;&amp;lt;div id=&amp;quot;root&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;root 안에 들어가는 모든 엘리먼트를 React DOM에서 관리하며 이것을 root DOM 노드라고 부른다. 일반적으로 React로 구현된 앱은 하나의 Root DOM 노드가 있다.&lt;/p&gt;
&lt;p&gt;React 엘리먼트를 root DOM 노드에 렌더링 하려면 &lt;code&gt;ReactDOM.render(element, document.getElementById(&amp;#39;root&amp;#39;))&lt;/code&gt;에 전달하면된다.&lt;/p&gt;
&lt;h2&gt;렌더링을 마친 엘리먼트를 수정하기&lt;/h2&gt;
&lt;p&gt;React 엘리먼트는 불변객체다. 생성한 이후에는 자식이나 속성을 변경할 수 없고 특정 시점의 UI를 보여준다.&lt;br&gt;UI를 업데이트하는 유일한 방법은 새로운 엘리먼트를 생성하고 이를 ReactDOM.render()에 전달하는 것이다.&lt;/p&gt;
&lt;h2&gt;변경된 부분만 업데이트 하기&lt;/h2&gt;
&lt;p&gt;ReactDOM은 해당 엘리먼트와 그 자식 엘리먼트를 이전의 엘리먼트와 비교하고 DOM을 원하는 상태로 만드는데 필요한 경우에만 DOM을 업데이트한다.&lt;/p&gt;
&lt;p&gt;매초 전체 UI를 다시그리도록 엘리먼트를 만들었지만 React DOM은 내용이 변경된 텍스트 노드만 업데이트한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function tick() {
  const element = (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;
      &amp;lt;h2&amp;gt;It is {new Date().toLocaleTimeString()}.&amp;lt;/h2&amp;gt;
    &amp;lt;/div&amp;gt;
  );
  ReactDOM.render(element, document.getElementById(&amp;#39;root&amp;#39;));
}

setInterval(tick, 1000);&lt;/code&gt;&lt;/pre&gt;</description>
      <category>독서/React</category>
      <category>el</category>
      <category>element</category>
      <category>react</category>
      <category>리액트</category>
      <category>리엑트</category>
      <category>엘리먼트</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/71</guid>
      <comments>https://soozl91.tistory.com/71#entry71comment</comments>
      <pubDate>Mon, 22 Mar 2021 17:48:13 +0900</pubDate>
    </item>
    <item>
      <title>[React] JSX란?</title>
      <link>https://soozl91.tistory.com/70</link>
      <description>&lt;h1&gt;jJSX&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/introducing-jsx.html&quot;&gt;공식 홈페이지(JSX)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=x7cQ3mrcKaY&quot;&gt;관심사 분리(유튜브)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 문자열도 HTMl도 아닌 코드
const element = &amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자바스크립트를 확장한 문법, React Element를 생성한다.&lt;/p&gt;
&lt;h2&gt;Expression&lt;/h2&gt;
&lt;p&gt;모든 자바스크립트 표현식이 사용 가능하고 &lt;code&gt;{ }&lt;/code&gt;를 사용하여 감싸면 된다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;const name = 'Eunsoo';
const el = &amp;lt;h1&amp;gt;{name}&amp;lt;/h1&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Compile&lt;/h2&gt;
&lt;p&gt;Babel's do&lt;code&gt;JSX =&amp;gt; React.createElement() =&amp;gt; React Element&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const element = (
  &amp;lt;h1 className=&quot;greeting&quot;&amp;gt;
    Hello, world!
  &amp;lt;/h1&amp;gt;
);

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

// 주의: 다음 구조는 단순화되었습니다
const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Attributes, Inline Style&lt;/h2&gt;
&lt;p&gt;JSX는 HTML보다는 JavaScript에 가깝기 때문에, React DOM은 HTML 어트리뷰트 이름 대신 camelCase 프로퍼티 명명 규칙을 사용한다. e.g. JSX에서 class는 className가&lt;br /&gt;되고 tabindex는 tabIndex가 된다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const element = &amp;lt;div tabIndex=&quot;0&quot;&amp;gt;&amp;lt;/div&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;React 에서 스타일을 적용할 때는 문자열 형태로 넣는것이 아닌 객체 형태로 넣어줘야한다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;const style = {
  backgroundColor: 'black',
  fontSize: '48px',
  fontWeight: 'bold'
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;XSS 방지&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;기본적으로 React DOM은 JSX에 삽입된 모든 값을 렌더링하기 전에 이스케이프 하므로, 애플리케이션에서 명시적으로 작성되지 않은 내용은 주입되지 않는다.&lt;/li&gt;
&lt;li&gt;모든 항목은 렌더링 되기 전에 문자열로 변환된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Tag&lt;/h2&gt;
&lt;p&gt;컴포넌트에 여러 요소가 있다면 반드시 부모 요소 하나로 감싸야함, Virtual Dom에서 컴포넌트 변화를 감지할 때 효율적으로 비교할 수 있도록 컴포넌트 내부는 하나의 Dom트리 구조로 이루어져야 한다 라는 규칙이&lt;br /&gt;있음&lt;/p&gt;
&lt;h2&gt;조건&lt;/h2&gt;
&lt;p&gt;표현식안에서는 if 조건문을 사용할 수 없지만 외부에서는 가능하다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 표현식 외부에서 if 문
function getGreeting(user) {
  if (user) {
    return &amp;lt;h1&amp;gt;Hello, {formatName(user)}!&amp;lt;/h1&amp;gt;;
  }
  return &amp;lt;h1&amp;gt;Hello, Stranger.&amp;lt;/h1&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;AND(&amp;amp;&amp;amp;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;true &amp;amp;&amp;amp; expression은 항상 expression으로 평가된다.&lt;/li&gt;
&lt;li&gt;false &amp;amp;&amp;amp; expression은 항상 false로 평가된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;따라서 &amp;amp;&amp;amp; 뒤의 엘리먼트는 조건이 true일때 출력이 됩니다. 조건이 false라면 React는 무시합니다. false로 평가될 수 있는 표현식을 반환하면 &amp;amp;&amp;amp; 뒤에 있는 표현식은 건너뛰지만 &lt;b&gt;false로 평가될&lt;br /&gt;수 있는 표현식이 반환된다&lt;/b&gt;.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;// &amp;amp;&amp;amp; 조건이 true일 경우 expresssion을 출력 false일 경우 null
console.log(true &amp;amp;&amp;amp; 1 &amp;gt; 0 &amp;amp;&amp;amp; 'success'); //success 
console.log(true &amp;amp;&amp;amp; 1 &amp;lt; 0 &amp;amp;&amp;amp; 'success'); //false &lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;OR(||)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;true &amp;amp;&amp;amp; expression은 항상 true 평가된다.&lt;/li&gt;
&lt;li&gt;false &amp;amp;&amp;amp; expression은 항상 expression으로 평가된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;// || 조건이 true일경우 조건 출력 false일 경우 expression 출력
console.log(1 &amp;gt; 0 || 'success'); //true 
console.log(1 &amp;lt; 0 || 'success'); //success&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;
const App = () =&amp;gt; {
  const name = undefined;
  return name;
}
export default App&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;리엑트 컴포넌트의 함수에서 &lt;code&gt;undefined&lt;/code&gt;를 반환하는 경우 리엑트에서 오류를 발생시킨다. &lt;code&gt;||&lt;/code&gt; 연산을 사용하여 값이 &lt;code&gt;undefined일&lt;/code&gt; 경우 기본값을 설정하여 오류를 피할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;const App = () =&amp;gt; {
  const name = undefined;
  return name || '값이 없다.';
}
export default App&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;반면 JSX 내부에서 undefined를 렌더링 하는것은 오류가 나지 않는다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const App = () =&amp;gt; {
  const name = undefined;
  return &amp;lt;h1&amp;gt;{name}&amp;lt;/h1&amp;gt;;
}
export default App&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Comment&lt;/h2&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;{/* 이렇게 */}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>독서/React</category>
      <category>jsx</category>
      <category>JSX문법</category>
      <category>react</category>
      <category>리액트</category>
      <category>리엑트</category>
      <category>문법</category>
      <category>사용법</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/70</guid>
      <comments>https://soozl91.tistory.com/70#entry70comment</comments>
      <pubDate>Mon, 22 Mar 2021 17:46:19 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA] Stream skip(), limit() 사용법</title>
      <link>https://soozl91.tistory.com/69</link>
      <description>&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;class StreamTest {

    @Test
    public void 자르기() {
        // 1 ~ 9 까지 배열 생성
        int[] one2nine = IntStream.range(1, 10).toArray();
        assertThat(one2nine).isEqualTo(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9});

        // 3번째 요소까지 스킵, 그 후 두개만
        int[] four2five = Arrays.stream(one2nine)
                .skip(3)
                .limit(2)
                .toArray();
        assertThat(four2five).isEqualTo(new int[]{4, 5});

        // 소스에서 처음 5개만
      int[] one2five = Arrays.stream(one2nine).limit(5).toArray();
      assertThat(one2five).isEqualTo(new int[]{1, 2, 3, 4, 5});
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Main/Java</category>
      <category>java Stream</category>
      <category>limit()</category>
      <category>skip()</category>
      <category>STREAM</category>
      <category>스트림사용법</category>
      <category>자바8</category>
      <category>자바스트림</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/69</guid>
      <comments>https://soozl91.tistory.com/69#entry69comment</comments>
      <pubDate>Wed, 17 Mar 2021 15:06:56 +0900</pubDate>
    </item>
    <item>
      <title>깨끗한 코드</title>
      <link>https://soozl91.tistory.com/68</link>
      <description>&lt;blockquote&gt;
&lt;p&gt;나는 내가 짠 코드에 자부심을 느끼고 내 이름을 적어두고 싶다. 내 코드를 읽고 고개를 끄덕이게 만들고 싶다. &amp;#39;이거 누가 작업한거에요?&amp;#39; 라는 질문에&lt;br&gt;&amp;#39;저요!&amp;#39; 라고 당당히 얘기하고 싶다. 설령 그게 질책이라도, 등에서 식은땀이 나도록 까여도 내 코드를 읽고 어드바이스를 준다면, 그리고 그걸로 내가 성장한다면 그걸로 좋다.&lt;/p&gt;
&lt;p&gt;그래서 이 책을 읽었다. &lt;del&gt;잘난척하고 싶어서. 카하하하핳&lt;/del&gt;&lt;br&gt;읽어주길 바란다면 쉽게 읽을 수 있어야 하니까. 술술 읽혀야 하니까.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;깨끗한 코드란?&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#39;안돌아가는 프로그램보다 돌아가는 쓰레기가 더 좋다. &amp;#39; 라고 안도하지말자&lt;/li&gt;
&lt;li&gt;나중에 손보겠다는 없다. 만들때 잘 만들자. &lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;르블랑의 법칙&lt;/strong&gt;, 나중은 결코 오지 않는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;기한을 맞추는 유일한 방법은 &lt;strong&gt;언제나 코드를 최대한 깨끗하게 유지하는 습관&lt;/strong&gt;이다.&lt;/li&gt;
&lt;li&gt;보는 사람에게 즐거움을 선사해야 한다.&lt;/li&gt;
&lt;li&gt;나쁜 코드는 나쁜 코드를 &amp;#39;유혹&amp;#39;한다. 나쁜 코드를 고치려면 오히려 더 나쁜 코드를 만들게 된다.&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;깨진 창문&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;누구도 상관하지 않는다는 인상을 픙기고 사람들이 관심을 끊는다.&lt;br&gt;창문이 더 깨져도 상관하지 않으며 마침내는 자발적으로 창문을 깬다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;나쁜 코드는 너무 많은 일을 하려 애쓰다가 의도가 뒤섞이고 목적이 흐려진다.&lt;blockquote&gt;
&lt;p&gt;깨끗한 코드는 한가지에 집중하고 주변 상황에 현혹되거나 오염되지 않은 채 한길만 걷는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;깨끗한 코드는 잘 쓴 문장처럼 읽힌다.&lt;blockquote&gt;
&lt;p&gt;해결할 문제의 긴장을 명확히 드러내고, 긴장이 쌓이며 클라이막스에 이르렀다가&lt;br&gt;명백한 해볍을 제시하며 긴장과 문제를 풀어내야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;반드시 필요한 내용만 담는다.&lt;/li&gt;
&lt;li&gt;다른 사람이 &lt;strong&gt;고치기 쉽다.&lt;/strong&gt; 읽기 쉬운 코드와 고치기 쉬운 코드는 엄연히 다르다.&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;테스트 케이스가 없는 코드는 깨끗한 코드가 아니다.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;깨끗한 코드는 주의 깊게 짰다는 느낌을 주고 고치려고 살펴봐도 딱히 손 댈곳이 없다.&lt;blockquote&gt;
&lt;p&gt;이미 작성자가 모든 사항을 고려했으므로, 고칠 궁리를 하다보면 언제나 제자리로 돌아온다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;초반부터 간단한 추상화를 고려한다.&lt;/li&gt;
&lt;li&gt;중복 줄이기&lt;/li&gt;
&lt;li&gt;표현력 높이기&lt;/li&gt;
&lt;li&gt;읽으면서 짐작한 대로 돌아가는 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;코드를 깨끗하게 짜고 나서..&lt;/h1&gt;
&lt;p&gt;시간이 지나도 언제나 깨끗하게 유지해야한다. 코드의 퇴보를 막아야한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;채크아웃할 때보다 좀 더 깨끗한 코드를 채크인 한다. (지속적인 개선)&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;보이스카우트 규칙&lt;/strong&gt;&lt;br&gt;캠프장은 처음 왔을 때보다 더 깨끗하게 해놓고 떠나라&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>독서/클린코드</category>
      <category>cleancode</category>
      <category>깨끗한코드</category>
      <category>깨진창문</category>
      <category>나쁜코드</category>
      <category>르블랑의법칙</category>
      <category>보이스카우트규칙</category>
      <category>엉클밥</category>
      <category>클린코드</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/68</guid>
      <comments>https://soozl91.tistory.com/68#entry68comment</comments>
      <pubDate>Thu, 11 Mar 2021 16:29:20 +0900</pubDate>
    </item>
    <item>
      <title>[단위테스트] Spring test</title>
      <link>https://soozl91.tistory.com/67</link>
      <description>&lt;h1&gt;Spring Test&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;테스트가 독립적이라고 해서 매번 스프링 컨텍스트, 즉 컨테이너를 새로 만드는 것은 매우 비효율적.&lt;br&gt;스프링 테스트는 사용하는 컨텍스트를 캐싱해ㅔ 여러 테스트에서 하나의 컨텍스트를 공유할 수 있는 방법을 제공한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;즉 동일한 컨텍스트 구성을 갖는 테스트끼리는 같은 컨텍스트를 공유하는것&lt;br&gt;공유는 메서드 사이에서만 가능한 게 아니라 여러 클래스 사이에서도 가능하다. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-test&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1. @RunWith(SpringJunit4ClassRunner.class)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ApplicationContext를 만들고 관리하는 작업을 할 수 있도록 jUnit의 기능을 확장&lt;/li&gt;
&lt;li&gt;jUnit에서는 테스트 메소드별로 객체를 따로 생성해 관리하는 반면 Spring-Test 라이브러리로 확장된 jUnit에서는 컨테이너 기술을 써서 싱글톤으로 관리되는 객체를 사용해 모든 테스트에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. @ContextConfiguration(locations = &amp;quot;classpath:xml파일위치&amp;quot;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;스프링 빈(Bean) 설정 파일의 위치를 지정&lt;/li&gt;
&lt;li&gt;@RunWith 어노테이션은 컨테이너를 생성하겠다는 의미인데, 어떤 파일을 참조할지 모르는 상태이기 때문에 이 어노테이션을 함께 써줘야함&lt;/li&gt;
&lt;li&gt;파일 위치의 루트는 &lt;code&gt;src/test/resources&lt;/code&gt;이며 운영 설정 파일을 이곳에 복사해놓고 사용해도 됨&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Main/Unit Test</category>
      <category>@ContextConfiguration</category>
      <category>@RunWith</category>
      <category>Spring-test</category>
      <author>키키수수</author>
      <guid isPermaLink="true">https://soozl91.tistory.com/67</guid>
      <comments>https://soozl91.tistory.com/67#entry67comment</comments>
      <pubDate>Thu, 25 Feb 2021 16:46:20 +0900</pubDate>
    </item>
  </channel>
</rss>