Π‘ΡΠ°ΡΡΡ Π±ΡΠ»Π° ΠΏΠ΅ΡΠ²ΠΎΠ½Π°ΡΠ°Π»ΡΠ½ΠΎ ΠΎΠΏΡΠ±Π»ΠΈΠΊΠΎΠ²Π°Π½Π° ΠΏΠΎ Π°Π΄ΡΠ΅ΡΡ carlos chac.in
Π‘ΠΌΠΎΡΡΠΈΡΠ΅ ΡΠ°ΠΊΠΆΠ΅:
ΠΠΎΡΡΡΠΈΠΉ Π½Π°ΠΏΠΈΡΠΎΠΊ ΠΠ΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΉ/ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅/ΠΠΎΠΌΠ±ΠΎΠΊ π₯ ΠΊΠ°ΠΊΠΎΠΉ?
ΠΠ°ΡΠ»ΠΎΡ Π§Π°ΡΠΈΠ½ β π½ – 13 Π°ΠΏΡΠ΅Π»Ρ – 5 ΠΌΠΈΠ½ΡΡ ΡΡΠ΅Π½ΠΈΡ
Π ΠΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΠΉ Java , ΠΠΆΠΎΡΡΠ° ΠΠ»ΠΎΡ Π΄Π°Π΅Ρ ΡΠ»Π΅Π΄ΡΡΡΡΡ ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°ΡΠΈΡ:
ΠΠ»Π°ΡΡΡ Π΄ΠΎΠ»ΠΆΠ½Ρ Π±ΡΡΡ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΌΠΈ, Π΅ΡΠ»ΠΈ ΡΠΎΠ»ΡΠΊΠΎ Π½Π΅Ρ ΠΎΡΠ΅Π½Ρ Π²Π΅ΡΠΊΠΎΠΉ ΠΏΡΠΈΡΠΈΠ½Ρ ΡΠ΄Π΅Π»Π°ΡΡ ΠΈΡ ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΌΠΈ… ΠΡΠ»ΠΈ ΠΊΠ»Π°ΡΡ Π½Π΅Π»ΡΠ·Ρ ΡΠ΄Π΅Π»Π°ΡΡ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΌ, ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎ ΠΎΠ³ΡΠ°Π½ΠΈΡΡΡΠ΅ Π΅Π³ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΡΠΈΠ²ΠΎΡΡΡ.
π© ΠΠ΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠ΅ ΠΠ±ΡΠ΅ΠΊΡΡ
ΠΠ±ΡΠ΅ΠΊΡ ΡΡΠΈΡΠ°Π΅ΡΡΡ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΌ, Π΅ΡΠ»ΠΈ Π΅Π³ΠΎ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡΡΡ ΠΏΠΎΡΠ»Π΅ Π΅Π³ΠΎ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ. ΠΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½Π°Ρ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΡ ΠΎΡ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΡ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ² ΡΠΈΡΠΎΠΊΠΎ ΠΏΡΠΈΠ·Π½Π°Π½Π° Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ°Π·ΡΠΌΠ½ΠΎΠΉ ΡΡΡΠ°ΡΠ΅Π³ΠΈΠΈ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΏΡΠΎΡΡΠΎΠ³ΠΎ ΠΈ Π½Π°Π΄Π΅ΠΆΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°. ΡΡΡΠ»ΠΊΠ°
- ΠΠ΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΡ ΡΠΎΠ·Π΄Π°ΡΡΡΡ ΠΎΠ΄ΠΈΠ½ ΡΠ°Π·, Π² ΡΠΎΠ³Π»Π°ΡΠΎΠ²Π°Π½Π½ΠΎΠΌ ΡΠΎΡΡΠΎΡΠ½ΠΈΠΈ, ΠΈ ΠΌΠΎΠ³ΡΡ Π±ΡΡΡ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎ ΡΠ°Π·Π΄Π΅Π»Π΅Π½Ρ
- ΠΡΠΎΠΈΠ·ΠΎΠΉΠ΄Π΅Ρ ΡΠ±ΠΎΠΉ, Π΅ΡΠ»ΠΈ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠ΅ Π°ΡΡΠΈΠ±ΡΡΡ ΠΎΡΡΡΡΡΡΠ²ΡΡΡ
- ΠΠ΅ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ Π½Π΅Π·Π°ΠΌΠ΅ΡΠ½ΠΎ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ ΠΏΡΠΈ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠ΅ Π² Π΄ΡΡΠ³ΠΎΠΉ ΠΊΠΎΠ΄
- ΠΠ΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΡ, Π΅ΡΡΠ΅ΡΡΠ²Π΅Π½Π½ΠΎ, ΠΏΠΎΡΠΎΠΊΠΎΠ±Π΅Π·ΠΎΠΏΠ°ΡΠ½Ρ ΠΈ ΠΏΠΎΡΡΠΎΠΌΡ ΠΌΠΎΠ³ΡΡ Π±ΡΡΡ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎ ΡΠ°Π·Π΄Π΅Π»Π΅Π½Ρ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΠΎΡΠΎΠΊΠ°ΠΌΠΈ
- ΠΠΈΠΊΠ°ΠΊΠΎΠ³ΠΎ ΡΡΠ΅Π·ΠΌΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΡ
- ΠΡΡΡΡΡΡΠ²ΠΈΠ΅ ΡΡΠ΅Π·ΠΌΠ΅ΡΠ½ΠΎΠΉ ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ
- ΠΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ² ΠΏΡΠΈΡΡΠ½ΠΎ ΠΏΠΈΡΠ°ΡΡ ΠΈ ΡΠΈΡΠ°ΡΡ
- ΠΠΈΠΊΠ°ΠΊΠΈΡ ΡΠ°Π±Π»ΠΎΠ½Π½ΡΡ ΡΡΡΠ°Π½ΠΎΠ²ΡΠΈΠΊΠΎΠ² ΠΈ Π΄ΠΎΠ±ΡΡΡΠΈΠΊΠΎΠ²
- ΠΠΈΠΊΠ°ΠΊΠΈΡ
ΡΡΠΎΠ΄Π»ΠΈΠ²ΡΡ
IDE-ΡΠ³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°Π½Π½ΡΡ
Ρ ΡΡ-ΠΊΠΎΠ΄Π°
,ΡΠ°Π²Π½ΠΎ
ΠΈtoString
ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ², ΠΊΠΎΡΠΎΡΡΠ΅ Π² ΠΊΠΎΠ½Π΅ΡΠ½ΠΎΠΌ ΠΈΡΠΎΠ³Π΅ ΡΠΎΡ ΡΠ°Π½ΡΡΡΡΡ Π² ΡΠΈΡΡΠ΅ΠΌΠ΅ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ Π²Π΅ΡΡΠΈΡΠΌΠΈ. ΡΡΡΠ»ΠΊΠ°
π§ ΠΠ°Π²Π°ΠΉΡΠ΅ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΡΠ΅ΠΌ ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ Π² Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΉ (Π²ΡΡΡΠ½ΡΡ β ):
Π‘Π»Π΅Π΄ΡΡΡΠΈΠΉ ΠΊΠ»Π°ΡΡ – ΡΡΠΎ ΡΠΎ, ΡΡΠΎ ΠΌΡ ΠΎΠ±ΡΡΠ½ΠΎ Π½Π°Π·ΡΠ²Π°Π΅ΠΌ POJO ΠΈΠ»ΠΈ Java-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ :
import java.util.Date; import java.util.List; import java.util.Objects; public class OldModel { private String fieldA; private Date fieldB; private Long fieldC; private ListfieldD; public OldModel() { } public String getFieldA() { return fieldA; } public void setFieldA(String fieldA) { this.fieldA = fieldA; } public Date getFieldB() { return fieldB; } public void setFieldB(Date fieldB) { this.fieldB = fieldB; } public Long getFieldC() { return fieldC; } public void setFieldC(Long fieldC) { this.fieldC = fieldC; } public List getFieldD() { return fieldD; } public void setFieldD(List fieldD) { this.fieldD = fieldD; } @Override public String toString() { return "OldModel{" + "fieldA='" + fieldA + '\'' + ", fieldB=" + fieldB + ", fieldC=" + fieldC + ", fieldD=" + fieldD + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; OldModel oldModel = (OldModel) o; return Objects.equals(getFieldA(), oldModel.getFieldA()) && Objects.equals(getFieldB(), oldModel.getFieldB()) && Objects.equals(getFieldC(), oldModel.getFieldC()) && Objects.equals(getFieldD(), oldModel.getFieldD()); } @Override public int hashCode() { return Objects.hash(getFieldA(), getFieldB(), getFieldC(), getFieldD()); } }
Π§ΡΠΎΠ±Ρ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°ΡΡ ΡΡΠΎ Π² Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ, ΠΌΡ Π΄ΠΎΠ»ΠΆΠ½Ρ:
π΄ ΠΠ»Π°ΡΡ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½:
- π Π‘Π΄Π΅Π»Π°ΠΉΡΠ΅ ΡΡΠΎΠΊ ΠΎΠΊΠΎΠ½ΡΠ°ΡΠ΅Π»ΡΠ½ΡΠΌ.
- π ΠΠ»ΠΈ ΡΠ΄Π΅Π»Π°ΠΉΡΠ΅ ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡ ΠΎΠΊΠΎΠ½ΡΠ°ΡΠ΅Π»ΡΠ½ΡΠΌ ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΡΠ°Π±ΡΠΈΡΠ½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ.
-public class OldModel { +public final class OldModel {
π Π‘Π΄Π΅Π»Π°ΠΉΡΠ΅ Π²ΡΠ΅ ΠΏΠΎΠ»Ρ Π·Π°ΠΊΡΡΡΡΠΌΠΈ ΠΈ ΠΎΠΊΠΎΠ½ΡΠ°ΡΠ΅Π»ΡΠ½ΡΠΌΠΈ
- private String fieldA; - private Date fieldB; - private Long fieldC; - private ListfieldD; + private final String fieldA; + private final Date fieldB; + private final Long fieldC; + private final List fieldD;
π§ ΠΠ±ΡΠ΅ΠΊΡ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±ΡΡΡ ΠΏΠΎΡΡΡΠΎΠ΅Π½ Π·Π° 1οΈ ΠΎΠ΄ΠΈΠ½ ΡΠ°Π³.
- public OldModel() { + public OldModel( + final String fieldA, + final Date fieldB, + final Long fieldC, + final ListfieldD) { + this.fieldA = fieldA; + this.fieldB = fieldB; + this.fieldC = fieldC; + this.fieldD = fieldD; }
π΄ ΠΠ΅ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠΉΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΠΎΠ³ΡΡ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠ°.
- public void setFieldA(String fieldA) { - this.fieldA = fieldA; - } . . // Remove all the setters .
β© ΠΡΠ»ΠΈ ΠΊΠ°ΠΊΠΎΠ΅-Π»ΠΈΠ±ΠΎ ΠΈΠ· ΠΏΠΎΠ»Π΅ΠΉ ΡΠ²Π»ΡΠ΅ΡΡΡ ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΌ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠΌ, Π²ΠΌΠ΅ΡΡΠΎ ΡΡΠΎΠ³ΠΎ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²ΡΡΠ΅ Π·Π°ΡΠΈΡΠ½ΡΡ ΠΊΠΎΠΏΠΈΡ ΡΡΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ°.
+ public Date getFieldB() { + return new Date(fieldB.getTime()); // Easy to forget about this :( + } + + public ListgetFieldD() { + return Collections.unmodifiableList(fieldD); // This is not great :( + }
Π ΡΠΎΠΌ , ΠΊΠ°ΠΊ Π²ΡΡΡΠ½ΡΡ β Π΄Π΅Π»Π°ΡΡ ΡΡΠΎ π€
Π§ΡΠΎ ΠΆ, ΡΡΠΎ Π±ΠΎΠ»ΡΡΠ°Ρ ΡΠ°Π±ΠΎΡΠ°, ΠΈ ΠΎΠ½Π° ΡΠ°ΠΊΠΆΠ΅ ΠΏΠΎΠ΄Π²Π΅ΡΠΆΠ΅Π½Π° ΠΎΡΠΈΠ±ΠΊΠ°ΠΌ, ΠΈ Π΄Π°ΠΆΠ΅ ΠΊΠΎΠ³Π΄Π° ΠΌΡ ΠΌΠΎΠΆΠ΅ΠΌ Π·Π°ΡΡΠ°Π²ΠΈΡΡ IDE ΠΈΠ·Π²Π΅ΡΠ³Π½ΡΡΡ Π²Π΅ΡΡ ΡΡΠΎΡ ΠΊΠΎΠ΄ Π΄Π»Ρ Π½Π°Ρ, Π½Π°ΠΌ Π²ΡΠ΅ ΡΠ°Π²Π½ΠΎ Π½ΡΠΆΠ½ΠΎ ΠΏΡΠΎΠ²Π΅ΡΠΈΡΡ ΠΈ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡ Π½Π΅ΠΊΠΎΡΠΎΡΡΠ΅ Π²Π΅ΡΠΈ.
π Π Π²ΠΎΡ ΡΠ΅Π·ΡΠ»ΡΡΠ°Ρ:
import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Objects; public final class OldModel { private final String fieldA; private final Date fieldB; private final Long fieldC; private final ListfieldD; public OldModel( final String fieldA, final Date fieldB, final Long fieldC, final List fieldD) { this.fieldA = fieldA; this.fieldB = fieldB; this.fieldC = fieldC; this.fieldD = fieldD; } public String getFieldA() { return this.fieldA; } public Date getFieldB() { return new Date(this.fieldB.getTime()); // Easy to forget about this :( } public Long getFieldC() { return this.fieldC; } public List getFieldD() { return Collections.unmodifiableList(this.fieldD); // This is not great :( } // toSting, equals and hashCode omitted }
π ΠΠ°Π²Π°ΠΉΡΠ΅ ΡΠ΄Π΅Π»Π°Π΅ΠΌ ΡΡΠΎ ΡΠ΅ΠΉΡΠ°Ρ , ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ ΠΏΡΠΎΡΡΠΎΠΉ ΡΠΏΠΎΡΠΎΠ±
ΠΠ΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΠ°Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°
ΠΡΠΎΡΠ΅ΡΡΠΎΡΡ Π°Π½Π½ΠΎΡΠ°ΡΠΈΠΉ Java Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΏΡΠΎΡΡΡΡ , Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΡΡ ΠΈ Π½Π΅ΠΏΡΠΎΡΠΈΠ²ΠΎΡΠ΅ΡΠΈΠ²ΡΡ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ² Π·Π½Π°ΡΠ΅Π½ΠΈΠΉ. ΠΠ΅ ΠΏΠΎΠ²ΡΠΎΡΡΠΉΡΠ΅ΡΡ, ΠΏΠΎΠΏΡΠΎΠ±ΡΠΉΡΠ΅ ΠΠ΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΉ, ΡΠ°ΠΌΡΠΉ ΠΏΠΎΠ»Π½ΡΠΉ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ Π² ΡΡΠΎΠΉ ΠΎΠ±Π»Π°ΡΡΠΈ!
ΠΠΊΠ»ΡΡΠ°ΡΡ immutables.org Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΡ ΠΎΡ Π²Π°ΡΠ΅Π³ΠΎ ΠΏΡΠΎΠ΅ΠΊΡΠ°:
ΠΠ°Π²ΠΈΡΠΈΠΌΠΎΡΡΡ ΠΎΡ Maven:
org.immutables value 2.8.3 provided
π· Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ
import org.immutables.value.Value; import java.util.Date; import java.util.List; @Value.Immutable public interface NewModel { String fieldA(); Date fieldB(); Long fieldC(); ListfieldD(); }
π© ΠΠΎΠΌΠΏΠΈΠ»ΠΈΡΡΠΉΡΠ΅ ΠΈ Π½Π°ΡΠ»Π°ΠΆΠ΄Π°ΠΉΡΠ΅ΡΡ
ΠΠΎΡΠ»Π΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π°Π½Π½ΠΎΡΠ°ΡΠΈΠΉ ΡΠ³Π΅Π½Π΅ΡΠΈΡΡΠ΅Ρ Π΄Π»Ρ Π²Π°Ρ ΡΠ»Π΅Π΄ΡΡΡΠΈΠΉ ΠΊΠΎΠ΄:
Π‘ΠΎΠ·Π΄Π°Π½Π½ΡΠΉ ΠΎΠΊΠΎΠ½ΡΠ°ΡΠ΅Π»ΡΠ½ΡΠΉ
ΠΊΠ»Π°ΡΡ, ΠΊΠΎΡΠΎΡΡΠΉ ΡΠ°ΡΡΠΈΡΡΠ΅Ρ Π½Π°ΠΏΠΈΡΠ°Π½Π½ΡΠΉ Π²ΡΡΡΠ½ΡΡ ΡΠΈΠΏ Π·Π½Π°ΡΠ΅Π½ΠΈΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ° ΠΈ ΡΠ΅Π°Π»ΠΈΠ·ΡΠ΅Ρ Π²ΡΠ΅ ΠΎΠ±ΡΡΠ²Π»Π΅Π½Π½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Π΄ΠΎΡΡΡΠΏΠ°, Π° ΡΠ°ΠΊΠΆΠ΅ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΠΏΠΎΠ»Ρ, ΠΌΠ΅ΡΠΎΠ΄Ρ, ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡΡ ΠΈ ΠΊΠ»Π°ΡΡ-ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡ .
ΠΠ΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΉ ΠΊΠ»Π°ΡΡ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΠ΅Π°Π»ΠΈΠ·ΡΠ΅Ρ Π°Π±ΡΡΡΠ°ΠΊΡΠ½ΡΠ΅ ΡΡΠ΅Π΄ΡΡΠ²Π° Π΄ΠΎΡΡΡΠΏΠ° ΠΊ Π°ΡΡΠΈΠ±ΡΡΠ°ΠΌ Π΄Π»Ρ ΡΠΊΠ°Π»ΡΡΠ½ΡΡ
ΠΏΡΠΈΠΌΠΈΡΠΈΠ²Π½ΡΡ
ΠΈ ΠΎΠ±ΡΠ΅ΠΊΡΠ½ΡΡ
ΡΡΡΠ»ΠΎΡΠ½ΡΡ
ΡΠΈΠΏΠΎΠ², ΠΏΡΠΈ ΡΡΠΎΠΌ Π΄Π»Ρ Π°ΡΡΠΈΠ±ΡΡΠΎΠ² ΠΊΠΎΠ»Π»Π΅ΠΊΡΠΈΠΈ ΠΈ Π΄ΡΡΠ³ΠΈΡ
ΡΠΈΠΏΠΎΠ² ΠΏΡΠ΅Π΄ΡΡΠΌΠΎΡΡΠ΅Π½Π° ΡΠΏΠ΅ΡΠΈΠ°Π»ΡΠ½Π°Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ°. java.lang. ΠΠ΅ΡΠΎΠ΄Ρ ΠΎΠ±ΡΠ΅ΠΊΡΠ° ΡΠ°Π²Π½ΠΎ
, Π₯ΡΡ-ΠΊΠΎΠ΄
ΠΈ toString
ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Ρ ΠΈ ΠΏΠΎΠ»Π½ΠΎΡΡΡΡ Π·Π°Π²ΠΈΡΡΡ ΠΎΡ Π·Π½Π°ΡΠ΅Π½ΠΈΠΉ Π°ΡΡΠΈΠ±ΡΡΠΎΠ², Π° Π½Π΅ ΠΎΡ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠ° ΠΎΠ±ΡΠ΅ΠΊΡΠ°.
ΠΠ΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠ΅ ΠΊΠ»Π°ΡΡΡ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΠ²Π»ΡΡΡΡΡ ΠΎΡΠ½ΠΎΠ²Π½ΡΠΌΠΈ (Π½ΠΎ Π½Π΅ Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½Π½ΡΠΌΠΈ) Π°ΡΡΠ΅ΡΠ°ΠΊΡΠ°ΠΌΠΈ ΠΈΡΡ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°, ΡΠΎΠ·Π΄Π°Π²Π°Π΅ΠΌΡΠΌΠΈ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠΌ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΡ Π°Π½Π½ΠΎΡΠ°ΡΠΈΠΉ.
βοΈ ΠΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠΎΠ·Π΄Π°Π½Π½ΡΠΉ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠΉ ΠΊΠ»Π°ΡΡ
public class App { public static void main(String[] args) { final ImmutableNewModel model = ImmutableNewModel.builder() .fieldA("A") .fieldB(new Date()) .fieldC(1L) .addFieldD("a", "b", "d") .addFieldD("e") .build(); System.out.println(model); } }
ΠΡΡ ΠΎΠ΄:
NewModel{fieldA=A, fieldB=Sat Apr 11 15:53:26 PDT 2020, fieldC=1, fieldD=[a, b, d, e]}
π ΠΠ΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΡΠ°Π²Π½Π΅Π½ΠΈΠΉ
16 | 69 | Π‘ΡΡΠΎΠΊΠΈ ΠΊΠΎΠ΄Π° Π΄Π»Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠ°Π½ΠΈΡ |
377 | 0 | Π‘ΡΡΠΎΠΊΠΈ ΠΊΠΎΠ΄Π° Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ |
β | β ΠΊ | ΠΠ°ΡΠΈΡΠ½Π°Ρ ΠΊΠΎΠΏΠΈΡ ΠΏΠΎΠ»Π΅ΠΉ |
β | β | Π‘Π²ΠΎΠ±ΠΎΠ΄Π½ΡΠΉ API Π΄Π»Ρ ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΡ |
β | β | Π‘ΡΡΠΎΠΈΡΠ΅Π»Ρ |
β | β | ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π½Π° ΠΎΠ±Π½ΡΠ»ΡΠ΅ΠΌΠΎΡΡΡ |
π Π‘Π³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ ΠΊΠΎΠ΄
ΠΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ Π² ΠΏΡΠΎΠ΅ΠΊΡΠ°Ρ
maven ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΎΡ Π±ΡΠ΄Π΅Ρ Π³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°ΡΡ ΠΈ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΈΠΌΠΏΠΎΡΡΠΈΡΠΎΠ²Π°ΡΡ ΡΠ³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ ΠΊΠΎΠ΄ Π² ΠΏΠ°ΠΏΠΊΡ target/generated_sources
ΠΈ ΠΈΠ· Π½Π΅Π΅, ΠΎΠ±ΡΠ°ΡΠΈΡΠ΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, ΡΡΠΎ Π² Π±ΠΎΠ»ΡΡΠΈΠ½ΡΡΠ²Π΅ ΡΠ»ΡΡΠ°Π΅Π² ΠΌΡ ΠΈΠ³Π½ΠΎΡΠΈΡΡΠ΅ΠΌ ΠΏΠ°ΠΏΠΊΡ target/
Π² ΡΠΈΡΡΠ΅ΠΌΠ°Ρ
ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ Π²Π΅ΡΡΠΈΠΉ (VCS), ΡΠ°ΠΊΠΈΡ
ΠΊΠ°ΠΊ git ΠΈ mercurial. ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ ΡΠ°ΠΉΠ» .gitignore
Π² ΠΏΡΠΎΠ΅ΠΊΡΠ΅. ΠΡΠΎΡ ΠΊΠΎΠ΄ Π½Π΅ Π½ΡΠΆΠ½ΠΎ ΠΏΠ΅ΡΠ΅Π΄Π°Π²Π°ΡΡ Π² ΡΠ΅Π½ΡΡΠ°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½ΡΠΉ VCS.
!! οΈ ΠΏΡΠ΅Π΄ΡΠΏΡΠ΅ΠΆΠ΄Π΅Π½ΠΈΠ΅: ΠΡΠΎ ΠΎΡΠ΅Π½Ρ ΠΌΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π° βοΈ βοΈ
package com.groupon.api.talks; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Objects; import org.immutables.value.Generated; /** * Immutable implementation of {@link NewModel}. ** Use the builder to create immutable instances: * {@code ImmutableNewModel.builder()}. */ @Generated(from = "NewModel", generator = "Immutables") @SuppressWarnings({"all"}) @javax.annotation.Generated("org.immutables.processor.ProxyProcessor") public final class ImmutableNewModel implements NewModel { private final String fieldA; private final Date fieldB; private final Long fieldC; private final List
fieldD; private ImmutableNewModel( String fieldA, Date fieldB, Long fieldC, List fieldD) { this.fieldA = fieldA; this.fieldB = fieldB; this.fieldC = fieldC; this.fieldD = fieldD; } /** * @return The value of the {@code fieldA} attribute */ @Override public String fieldA() { return fieldA; } /** * @return The value of the {@code fieldB} attribute */ @Override public Date fieldB() { return fieldB; } /** * @return The value of the {@code fieldC} attribute */ @Override public Long fieldC() { return fieldC; } /** * @return The value of the {@code fieldD} attribute */ @Override public List fieldD() { return fieldD; } /** * Copy the current immutable object by setting a value for the {@link NewModel#fieldA() fieldA} attribute. * An equals check used to prevent copying of the same value by returning {@code this}. * @param value A new value for fieldA * @return A modified copy of the {@code this} object */ public final ImmutableNewModel withFieldA(String value) { String newValue = Objects.requireNonNull(value, "fieldA"); if (this.fieldA.equals(newValue)) return this; return new ImmutableNewModel(newValue, this.fieldB, this.fieldC, this.fieldD); } /** * Copy the current immutable object by setting a value for the {@link NewModel#fieldB() fieldB} attribute. * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}. * @param value A new value for fieldB * @return A modified copy of the {@code this} object */ public final ImmutableNewModel withFieldB(Date value) { if (this.fieldB == value) return this; Date newValue = Objects.requireNonNull(value, "fieldB"); return new ImmutableNewModel(this.fieldA, newValue, this.fieldC, this.fieldD); } /** * Copy the current immutable object by setting a value for the {@link NewModel#fieldC() fieldC} attribute. * An equals check used to prevent copying of the same value by returning {@code this}. * @param value A new value for fieldC * @return A modified copy of the {@code this} object */ public final ImmutableNewModel withFieldC(Long value) { Long newValue = Objects.requireNonNull(value, "fieldC"); if (this.fieldC.equals(newValue)) return this; return new ImmutableNewModel(this.fieldA, this.fieldB, newValue, this.fieldD); } /** * Copy the current immutable object with elements that replace the content of {@link NewModel#fieldD() fieldD}. * @param elements The elements to set * @return A modified copy of {@code this} object */ public final ImmutableNewModel withFieldD(String... elements) { List newValue = createUnmodifiableList(false, createSafeList(Arrays.asList(elements), true, false)); return new ImmutableNewModel(this.fieldA, this.fieldB, this.fieldC, newValue); } /** * Copy the current immutable object with elements that replace the content of {@link NewModel#fieldD() fieldD}. * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}. * @param elements An iterable of fieldD elements to set * @return A modified copy of {@code this} object */ public final ImmutableNewModel withFieldD(Iterable elements) { if (this.fieldD == elements) return this; List newValue = createUnmodifiableList(false, createSafeList(elements, true, false)); return new ImmutableNewModel(this.fieldA, this.fieldB, this.fieldC, newValue); } /** * This instance is equal to all instances of {@code ImmutableNewModel} that have equal attribute values. * @return {@code true} if {@code this} is equal to {@code another} instance */ @Override public boolean equals(Object another) { if (this == another) return true; return another instanceof ImmutableNewModel && equalTo((ImmutableNewModel) another); } private boolean equalTo(ImmutableNewModel another) { return fieldA.equals(another.fieldA) && fieldB.equals(another.fieldB) && fieldC.equals(another.fieldC) && fieldD.equals(another.fieldD); } /** * Computes a hash code from attributes: {@code fieldA}, {@code fieldB}, {@code fieldC}, {@code fieldD}. * @return hashCode value */ @Override public int hashCode() { int h = 5381; h += (h << 5) + fieldA.hashCode(); h += (h << 5) + fieldB.hashCode(); h += (h << 5) + fieldC.hashCode(); h += (h << 5) + fieldD.hashCode(); return h; } /** * Prints the immutable value {@code NewModel} with attribute values. * @return A string representation of the value */ @Override public String toString() { return "NewModel{" + + fieldA + ", fieldB=" + fieldB + ", fieldC=" + fieldC + ", fieldD=" + fieldD + "}"; } /** * Creates an immutable copy of a {@link NewModel} value. * Uses accessors to get values to initialize the new immutable instance. * If an instance is already immutable, it is returned as is. * @param instance The instance to copy * @return A copied immutable NewModel instance */ public static ImmutableNewModel copyOf(NewModel instance) { if (instance instanceof ImmutableNewModel) { return (ImmutableNewModel) instance; } return ImmutableNewModel.builder() .from(instance) .build(); } /** * Creates a builder for {@link ImmutableNewModel ImmutableNewModel}. * * ImmutableNewModel.builder() * .fieldA(String) // required {@link NewModel#fieldA() fieldA} * .fieldB(Date) // required {@link NewModel#fieldB() fieldB} * .fieldC(Long) // required {@link NewModel#fieldC() fieldC} * .addFieldD|addAllFieldD(String) // {@link NewModel#fieldD() fieldD} elements * .build(); ** @return A new ImmutableNewModel builder */ public static ImmutableNewModel.Builder builder() { return new ImmutableNewModel.Builder(); } /** * Builds instances of type {@link ImmutableNewModel ImmutableNewModel}. * Initialize attributes and then invoke the {@link #build()} method to create an * immutable instance. *{@code Builder} is not thread-safe and generally should not be stored in a field or collection, * but instead used immediately to create instances. */ @Generated(from = "NewModel", generator = "Immutables") public static final class Builder { private static final long INIT_BIT_FIELD_A = 0x1L; private static final long INIT_BIT_FIELD_B = 0x2L; private static final long INIT_BIT_FIELD_C = 0x4L; private long initBits = 0x7L; private String fieldA; private Date fieldB; private Long fieldC; private List
fieldD = new ArrayList (); private Builder() { } /** * Fill a builder with attribute values from the provided {@code NewModel} instance. * Regular attribute values will be replaced with those from the given instance. * Absent optional values will not replace present values. * Collection elements and entries will be added, not replaced. * @param instance The instance from which to copy values * @return {@code this} builder for use in a chained invocation */ public final Builder from(NewModel instance) { Objects.requireNonNull(instance, "instance"); fieldA(instance.fieldA()); fieldB(instance.fieldB()); fieldC(instance.fieldC()); addAllFieldD(instance.fieldD()); return this; } /** * Initializes the value for the {@link NewModel#fieldA() fieldA} attribute. * @param fieldA The value for fieldA * @return {@code this} builder for use in a chained invocation */ public final Builder fieldA(String fieldA) { this.fieldA = Objects.requireNonNull(fieldA, "fieldA"); initBits &= ~INIT_BIT_FIELD_A; return this; } /** * Initializes the value for the {@link NewModel#fieldB() fieldB} attribute. * @param fieldB The value for fieldB * @return {@code this} builder for use in a chained invocation */ public final Builder fieldB(Date fieldB) { this.fieldB = Objects.requireNonNull(fieldB, "fieldB"); initBits &= ~INIT_BIT_FIELD_B; return this; } /** * Initializes the value for the {@link NewModel#fieldC() fieldC} attribute. * @param fieldC The value for fieldC * @return {@code this} builder for use in a chained invocation */ public final Builder fieldC(Long fieldC) { this.fieldC = Objects.requireNonNull(fieldC, "fieldC"); initBits &= ~INIT_BIT_FIELD_C; return this; } /** * Adds one element to {@link NewModel#fieldD() fieldD} list. * @param element A fieldD element * @return {@code this} builder for use in a chained invocation */ public final Builder addFieldD(String element) { this.fieldD.add(Objects.requireNonNull(element, "fieldD element")); return this; } /** * Adds elements to {@link NewModel#fieldD() fieldD} list. * @param elements An array of fieldD elements * @return {@code this} builder for use in a chained invocation */ public final Builder addFieldD(String... elements) { for (String element : elements) { this.fieldD.add(Objects.requireNonNull(element, "fieldD element")); } return this; } /** * Sets or replaces all elements for {@link NewModel#fieldD() fieldD} list. * @param elements An iterable of fieldD elements * @return {@code this} builder for use in a chained invocation */ public final Builder fieldD(Iterable elements) { this.fieldD.clear(); return addAllFieldD(elements); } /** * Adds elements to {@link NewModel#fieldD() fieldD} list. * @param elements An iterable of fieldD elements * @return {@code this} builder for use in a chained invocation */ public final Builder addAllFieldD(Iterable elements) { for (String element : elements) { this.fieldD.add(Objects.requireNonNull(element, "fieldD element")); } return this; } /** * Builds a new {@link ImmutableNewModel ImmutableNewModel}. * @return An immutable instance of NewModel * @throws java.lang.IllegalStateException if any required attributes are missing */ public ImmutableNewModel build() { if (initBits != 0) { throw new IllegalStateException(formatRequiredAttributesMessage()); } return new ImmutableNewModel(fieldA, fieldB, fieldC, createUnmodifiableList(true, fieldD)); } private String formatRequiredAttributesMessage() { List attributes = new ArrayList<>(); if ((initBits & INIT_BIT_FIELD_A) != 0) attributes.add("fieldA"); if ((initBits & INIT_BIT_FIELD_B) != 0) attributes.add("fieldB"); if ((initBits & INIT_BIT_FIELD_C) != 0) attributes.add("fieldC"); return "Cannot build NewModel, some of required attributes are not set " + attributes; } } private static List createSafeList(Iterable extends T> iterable, boolean checkNulls, boolean skipNulls) { ArrayList list; if (iterable instanceof Collection>) { int size = ((Collection>) iterable).size(); if (size == 0) return Collections.emptyList(); list = new ArrayList<>(); } else { list = new ArrayList<>(); } for (T element : iterable) { if (skipNulls && element == null) continue; if (checkNulls) Objects.requireNonNull(element, "element"); list.add(element); } return list; } private static List createUnmodifiableList(boolean clone, List list) { switch(list.size()) { case 0: return Collections.emptyList(); case 1: return Collections.singletonList(list.get(0)); default: if (clone) { return Collections.unmodifiableList(new ArrayList<>(list)); } else { if (list instanceof ArrayList>) { ((ArrayList>) list).trimToSize(); } return Collections.unmodifiableList(list); } } } }
ΠΡΠ²ΠΎΠ΄
Π―Π·ΡΠΊ Java ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ Π΅ΡΠ΅ Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΡΠΌ, Π΅ΡΠ»ΠΈ ΠΌΡ Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ Π½Π°Π΄Π»Π΅ΠΆΠ°ΡΠΈΠ΅ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ Π΄Π»Ρ ΡΡΠΎΠΉ ΡΠ°Π±ΠΎΡΡ, ΠΈ Π² ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ ΠΌΠ½ΠΎΠ³ΠΈΡ Π»Π΅Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΡ ΠΊΠΎΠ΄Π° Π±ΡΠ»Π° ΠΏΠΎΠ»Π΅Π·Π½ΡΠΌ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ΠΌ, ΠΎΠ±Π»Π΅Π³ΡΠ°ΡΡΠΈΠΌ Π½Π°ΡΡ ΠΆΠΈΠ·Π½Ρ Π² ΡΠΊΠΎΡΠΈΡΡΠ΅ΠΌΠ΅ Java. ΠΠΎΡΡΠΈΠΆΠ΅Π½ΠΈΠ΅ Ρ ΠΎΡΠΎΡΠ΅Π³ΠΎ ΡΡΠΎΠ²Π½Ρ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΠΎΡΡΠΈ Π² Π½Π°ΡΠΈΡ ΠΊΠΎΠ΄ΠΎΠ²ΡΡ Π±Π°Π·Π°Ρ ΡΡΠ΅Π±ΡΠ΅Ρ Π±ΠΎΠ»ΡΡΠΈΡ ΡΡΠΈΠ»ΠΈΠΉ ΠΏΡΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΡΡΠΎΠ³ΠΎ Π²ΡΡΡΠ½ΡΡ, ΠΈ ΡΡΠΎ ΠΏΠΎΠ΄Π²Π΅ΡΠΆΠ΅Π½ΠΎ Π½Π΅ΠΏΡΠ΅Π΄Π½Π°ΠΌΠ΅ΡΠ΅Π½Π½ΡΠΌ ΠΎΡΠΈΠ±ΠΊΠ°ΠΌ, ΡΡΠΎΠ±Ρ ΠΈΠ·Π±Π΅ΠΆΠ°ΡΡ ΡΡΠΎΠ³ΠΎ ΠΈ ΡΠΌΠ΅Π½ΡΡΠΈΡΡ Π½Π°ΡΡ ΠΊΠΎΠ΄ΠΎΠ²ΡΡ Π±Π°Π·Ρ (ΠΌΠ΅Π½ΡΡΠ΅ ΠΊΠΎΠ΄Π°, ΠΌΠ΅Π½ΡΡΠ΅ ΠΎΡΠΈΠ±ΠΎΠΊ), ΠΌΡ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Immutables.org Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°.
ΠΡΠΈΠ³ΠΈΠ½Π°Π»: “https://dev.to/cchacin/immutability-in-java-made-easy-372g”