String immutable vs StringBuilder mutable


// String immutable vs. StringBuilder mutable
// + operator (new StringBuilder(String.valueOf(str1)).append(str2).toString();
String a = "Hello";
String b = "Hello";
String c = a;
String d = "Hel" + "lo";
String e = "Hello" + "";
String f = a + ""; // String + StringLiteral => new String
String g = "";
String h = a + g; // String + String -> new String
String s = new String("Hello"); // new String
String t = new String("Hello"); // new String
String u = s + new String(""); // String + String -> new String
String v = s + new String(""); // String + String -> new String
String x = s.concat("~"); // concat creates new String
String y = s.concat("~"); // concat creates new String
System.out.println(getReference(a) + " a=" + a + " hashCode=" + a.hashCode());
System.out.println(getReference(b) + " b=" + b + " hashCode=" + b.hashCode());
System.out.println(getReference(c) + " c=" + c + " hashCode=" + c.hashCode());
System.out.println(getReference(d) + " d=" + d + " hashCode=" + d.hashCode());
System.out.println(getReference(e) + " e=" + e + " hashCode=" + e.hashCode());
System.out.println("a==e " + (a == e));
System.out.println(getReference(f) + " f=" + f + " hashCode=" + f.hashCode());
System.out.println("a==f " + (a == f));
System.out.println(getReference(g) + " g=" + g + " hashCode=" + g.hashCode());
System.out.println(getReference(h) + " h=" + h + " hashCode=" + h.hashCode());
System.out.println("a==h " + (a == h));
System.out.println(getReference(s) + " s=" + s + " hashCode=" + s.hashCode());
System.out.println("a==s " + (a == s));
System.out.println(getReference(t) + " t=" + t + " hashCode=" + t.hashCode());
System.out.println("s==t " + (s == t));
System.out.println(getReference(u) + " u=" + u + " hashCode=" + u.hashCode());
System.out.println(getReference(v) + " v=" + v + " hashCode=" + v.hashCode());
System.out.println("u==v " + (u == v));
System.out.println(getReference(x) + " x=" + x + " hashCode=" + x.hashCode());
System.out.println(getReference(y) + " y=" + y + " hashCode=" + y.hashCode());
System.out.println("x==y " + (x == y));

String str1 = "P";
String str2 = "P";
String str3 = str1 + str2;
String str4 = str1.concat(str2);
System.out.println(getReference(str1) + " str1=" + str1 + " hashCode=" + str1.hashCode());
System.out.println(getReference(str2) + " str2=" + str2 + " hashCode=" + str2.hashCode());
System.out.println(getReference(str3) + " str3=" + str3 + " hashCode=" + str3.hashCode());
System.out.println(getReference(str4) + " str4=" + str4 + " hashCode=" + str4.hashCode());
System.out.println("str3==str4 " + (str3 == str4));

 

 
java.lang.String@5a39699c a=Hello hashCode=69609650
java.lang.String@5a39699c b=Hello hashCode=69609650
java.lang.String@5a39699c c=Hello hashCode=69609650
java.lang.String@5a39699c d=Hello hashCode=69609650
java.lang.String@5a39699c e=Hello hashCode=69609650
a==e true
java.lang.String@3cb5cdba f=Hello hashCode=69609650
a==f false
java.lang.String@56cbfb61 g= hashCode=0
java.lang.String@1134affc h=Hello hashCode=69609650
a==h false
java.lang.String@d041cf s=Hello hashCode=69609650
a==s false
java.lang.String@129a8472 t=Hello hashCode=69609650
s==t false
java.lang.String@1b0375b3 u=Hello hashCode=69609650
java.lang.String@2f7c7260 v=Hello hashCode=69609650
u==v false
java.lang.String@2d209079 x=Hello~ hashCode=-2137068020
java.lang.String@6bdf28bb y=Hello~ hashCode=-2137068020
x==y false
java.lang.String@6b71769e str1=P hashCode=80
java.lang.String@6b71769e str2=P hashCode=80
java.lang.String@2752f6e2 str3=PP hashCode=2560
java.lang.String@e580929 str4=PP hashCode=2560
str3==str4 false

String vs String Literal vs StringBuilder

// String Literal uses String common pool.
// String is immutable object.
// StringBuilder is mutable object.

// + operator (new StringBuilder(String.valueOf(str1)).append(str2).toString();
String str1 = "P";
String str2 = "P";
String str3 = str1 + str2;

// str1.concat(str2) method creates new String
String str4 = str1.concat(str2);

Java Double Colon Operator

Java :: 연산자 (Double Colon Operator)는 람다식을 대체하여 메서드 참조(method reference)로 사용된다. 즉, 람다식이 사용될 수 있는 Functional Interface Implementation에서만 사용 가능하다.

    • Using Lambda
      Comparator<Person> c = (Person p1, Person p2) ->
                          p1.getName().compareTo(p2.getName());  
      
    • Using Lambda with type interference
      Comparator<Person> c = (p1, p2) -> p1.getName().CompareTo(p2.getName());
    • Using method reference ( :: operator)
      Comparator<Person> c = Comparator.comparing(Person::getName);
    • Method reference  ( :: operator)
      Function<Person, String> getName = Person::getName; // Person->String
      String name = getName.apply(person1); 
      
    • Method reference ( :: operator)는 람다식과 동일한 처리를 하는 식이지만 메소드 본문을 제공하는 대신 기존 메소드를 이름으로 참조한다.
      Function<Double, Double> sq = (Double x) -> x * x; // lambda 
      double result = sq.apply(3); // 3 * 3 = 9
       
      Function<Double, Double> sq2 = MyClass::square; // MyClass에 정의된 square 정적 메소드
      double result2 = sq2.apply(3); // 3 * 3 = 9
      BiFunction<Double, Double, Double> add = (x, y) -> x + y; // lambda
      double result = add.apply(3.1, 3.2); // 3.1 + 3.2 = 6.3
      
      BiFunction<Double, Double, Double> add2 = MyClass::sum; // MyClass에 정의된 sum 정적 메소드 
      double result2 = add2.apply(3.1, 3.2); // 3.1 + 3.2 = 6.3 

       

Java Lambda Default Functional Interface

Java Lambda 기본 함수형 인터페이스 java.util.function 패키지에 정의되어 있음.

    • Functions
      public interface Function<T, R> {
        
        R apply(T t);
      }
    • Suppliers
      public interface Supplier<T> {
        T get();
      }
    • Consumers
      public interface Consumer<T> {
      
        void accept(T t); 
      }
    • Predicates
      public interface Predicate<T> {
      
        boolean test(T t); 
      }
    • Operators
      public interface UnaryOperator<T> extends Function<T, T> {
        static <T> UnaryOperator<T> identity() {
          return t -> t;
        }
      }
      
      public interface BinaryOperator<T> extends BiFunction<T,T,T> {
      
        public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
          Objects.requireNonNull(comparator);
          return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
        }
      
        public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
          Objects.requireNonNull(comparator);
          return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
        }
      }