From b24c323cdbca06a710133bd577e208a8ef5d9b45 Mon Sep 17 00:00:00 2001 From: Keesun Baik Date: Tue, 22 Mar 2022 21:46:26 -0700 Subject: [PATCH 1/8] Effective Java Part 2 and 3 --- .gitignore | 33 ++ .mvn/wrapper/maven-wrapper.jar | Bin 0 -> 58727 bytes .mvn/wrapper/maven-wrapper.properties | 2 + mvnw | 316 ++++++++++++++++++ mvnw.cmd | 188 +++++++++++ pom.xml | 60 ++++ .../chapter01/item01/ActionEnum.java | 11 + .../chapter01/item01/AdvancedSettings.java | 8 + .../me/whiteship/chapter01/item01/App.java | 13 + .../whiteship/chapter01/item01/AppConfig.java | 15 + .../chapter01/item01/Difficulty.java | 6 + .../chapter01/item01/HelloService.java | 28 ++ .../chapter01/item01/HelloServiceFactory.java | 28 ++ .../whiteship/chapter01/item01/ListQuiz.java | 24 ++ .../me/whiteship/chapter01/item01/Order.java | 38 +++ .../chapter01/item01/OrderStatus.java | 12 + .../whiteship/chapter01/item01/Product.java | 18 + .../whiteship/chapter01/item01/Settings.java | 23 ++ .../chapter01/item02/builder/BuilderTest.java | 10 + .../item02/builder/NutritionFacts.java | 57 ++++ .../chapter01/item02/freeze/FreezeTest.js | 10 + .../chapter01/item02/freeze/Person.java | 24 ++ .../item02/hierarchicalbuilder/Calzone.java | 31 ++ .../item02/hierarchicalbuilder/NyPizza.java | 32 ++ .../item02/hierarchicalbuilder/Pizza.java | 33 ++ .../item02/hierarchicalbuilder/PizzaTest.java | 20 ++ .../illegalargumentexception/Order.java | 20 ++ .../item02/javabeans/NutritionFacts.java | 53 +++ .../NutritionFacts.java | 46 +++ .../item02/varargs/VarargsSamples.java | 17 + .../chapter01/item03/enumtype/Elvis.java | 16 + .../item03/enumtype/EnumElvisReflection.java | 15 + .../enumtype/EnumElvisSerialization.java | 23 ++ .../chapter01/item03/field/Concert.java | 28 ++ .../chapter01/item03/field/Elvis.java | 40 +++ .../item03/field/ElvisReflection.java | 21 ++ .../item03/field/ElvisSerialization.java | 23 ++ .../chapter01/item03/field/IElvis.java | 8 + .../functionalinterface/DefaultFunctions.java | 24 ++ .../functionalinterface/MyFunction.java | 11 + .../functionalinterface/UsageOfFunctions.java | 21 ++ .../item03/methodreference/Person.java | 42 +++ .../chapter01/item03/serialization/Book.java | 67 ++++ .../serialization/SerializationExample.java | 36 ++ .../item03/staticfactory/Concert.java | 16 + .../chapter01/item03/staticfactory/Elvis.java | 26 ++ .../item03/staticfactory/MetaElvis.java | 32 ++ .../item03/staticfactory/Singer.java | 6 + .../chapter01/item04/DefaultUtilityClass.java | 9 + .../chapter01/item04/UtilityClass.java | 26 ++ .../chapter01/item05/DefaultDictionary.java | 18 + .../chapter01/item05/Dictionary.java | 10 + .../chapter01/item05/MockDictionary.java | 15 + .../DictionaryFactory.java | 9 + .../dependencyinjection/SpellChecker.java | 29 ++ .../DefaultDictionaryFactory.java | 11 + .../factorymethod/DictionaryFactory.java | 9 + .../factorymethod/MockDictionaryFactory.java | 12 + .../item05/factorymethod/SpellChecker.java | 25 ++ .../chapter01/item05/package-info.java | 1 + .../item05/singleton/SpellChecker.java | 25 ++ .../chapter01/item05/springioc/App.java | 13 + .../chapter01/item05/springioc/AppConfig.java | 10 + .../item05/springioc/SpellChecker.java | 26 ++ .../item05/springioc/SpringDictionary.java | 21 ++ .../item05/staticutils/SpellChecker.java | 23 ++ .../me/whiteship/chapter01/item06/Client.java | 8 + .../chapter01/item06/Deprecation.java | 18 + .../chapter01/item06/RegularExpression.java | 18 + .../chapter01/item06/RomanNumerals.java | 31 ++ .../whiteship/chapter01/item06/Strings.java | 18 + .../me/whiteship/chapter01/item06/Sum.java | 19 ++ .../chapter01/item07/cache/CacheKey.java | 37 ++ .../chapter01/item07/cache/Post.java | 39 +++ .../item07/cache/PostRepository.java | 29 ++ .../item07/executor/ExecutorsExample.java | 31 ++ .../chapter01/item07/listener/ChatRoom.java | 27 ++ .../chapter01/item07/listener/User.java | 8 + .../chapter01/item07/optional/Channel.java | 17 + .../chapter01/item07/optional/MemberShip.java | 8 + .../chapter01/item07/reference/BigObject.java | 4 + .../item07/reference/BigObjectReference.java | 15 + .../reference/PhantomReferenceExample.java | 28 ++ .../reference/SoftReferenceExample.java | 19 ++ .../reference/WeakReferenceExample.java | 19 ++ .../item07/stack/EmptyStackException.java | 5 + .../chapter01/item07/stack/Stack.java | 52 +++ .../chapter01/item08/autoclosable/App.java | 11 + .../autoclosable/AutoClosableIsGood.java | 25 ++ .../chapter01/item08/cleaner/BigObject.java | 27 ++ .../item08/cleaner/CleanerIsNotGood.java | 21 ++ .../item08/cleaner_as_a_safetynet/Adult.java | 10 + .../item08/cleaner_as_a_safetynet/Room.java | 38 +++ .../cleaner_as_a_safetynet/Teenager.java | 14 + .../chapter01/item08/finalizer/App.java | 36 ++ .../item08/finalizer/FinalizerIsBad.java | 9 + .../item08/finalizer_attack/Account.java | 21 ++ .../finalizer_attack/BrokenAccount.java | 16 + .../item08/outerclass/LambdaExample.java | 22 ++ .../item08/outerclass/OuterClass.java | 35 ++ .../chapter01/item09/puzzler/Copy.java | 37 ++ .../item09/suppress/BadBufferedReader.java | 23 ++ .../chapter01/item09/suppress/TopLine.java | 18 + .../chapter01/item09/tryfinally/Copy.java | 31 ++ .../chapter01/item09/tryfinally/TopLine.java | 22 ++ .../item09/trywithresources/Copy.java | 24 ++ .../item09/trywithresources/TopLine.java | 21 ++ .../trywithresources/TopLineWithDefault.java | 23 ++ .../item10/CaseInsensitiveString.java | 44 +++ .../me/whiteship/chapter02/item10/Color.java | 3 + .../chapter02/item10/EqualsInJava.java | 24 ++ .../chapter02/item10/PhoneNumber.java | 30 ++ .../me/whiteship/chapter02/item10/Point.java | 49 +++ .../item10/autovalue/AutoValueTest.java | 9 + .../chapter02/item10/autovalue/Point.java | 18 + .../item10/composition/ColorPoint.java | 36 ++ .../item10/inheritance/ColorPoint.java | 48 +++ .../item10/inheritance/CounterPoint.java | 18 + .../item10/inheritance/CounterPointTest.java | 30 ++ .../item10/inheritance/SmellPoint.java | 25 ++ .../item10/inheritance/SmellPointTest.java | 16 + .../chapter02/item10/lombok/LombokTest.java | 9 + .../chapter02/item10/lombok/Point.java | 21 ++ .../chapter02/item10/record/Point.java | 5 + .../chapter02/item10/record/PointTest.java | 14 + .../chapter02/item11/guava/PhoneNumber.java | 55 +++ .../item11/hashcode/PhoneNumber.java | 78 +++++ .../item11/hashtable/HashMapTest.java | 28 ++ .../chapter02/item11/package-info.java | 1 + .../chapter02/item12/PhoneNumber.java | 83 +++++ .../chapter02/item13/EmptyStackException.java | 4 + .../whiteship/chapter02/item13/HashTable.java | 87 +++++ .../chapter02/item13/PhoneNumber.java | 82 +++++ .../me/whiteship/chapter02/item13/Stack.java | 74 ++++ .../item13/clone_use_constructor/Item.java | 17 + .../item13/clone_use_constructor/SubItem.java | 20 ++ .../copy_constructor/HashSetExample.java | 19 ++ .../chapter02/item13/exception/MyApp.java | 26 ++ .../item13/exception/MyException.java | 4 + .../chapter02/item13/inheritance/Shape.java | 32 ++ .../chapter02/item13/inheritance/Square.java | 22 ++ .../item13/treeset/TreeSetExample.java | 28 ++ .../item14/CaseInsensitiveString.java | 41 +++ .../chapter02/item14/CompareToConvention.java | 36 ++ .../chapter02/item14/PhoneNumber.java | 107 ++++++ .../whiteship/chapter02/item14/WordList.java | 16 + .../item14/composition/NamedPoint.java | 25 ++ .../chapter02/item14/composition/Point.java | 20 ++ .../item14/decimal/DecimalIsNotCorrect.java | 15 + .../chapter02/item14/decimal/IntOverflow.java | 9 + .../item14/interitance/NamedPoint.java | 49 +++ .../chapter02/item14/interitance/Point.java | 28 ++ src/main/resources/application.properties | 1 + .../chapter01/item03/field/ConcertTest.java | 18 + .../chapter01/item03/field/MockElvis.java | 13 + .../dependencyinjection/SpellCheckerTest.java | 14 + .../item05/staticutils/SpellCheckerTest.java | 14 + .../item07/cache/PostRepositoryTest.java | 61 ++++ .../item07/listener/ChatRoomTest.java | 33 ++ .../item07/optional/ChannelTest.java | 18 + .../item08/finalizer_attack/AccountTest.java | 28 ++ 161 files changed, 4462 insertions(+) create mode 100644 .gitignore create mode 100644 .mvn/wrapper/maven-wrapper.jar create mode 100644 .mvn/wrapper/maven-wrapper.properties create mode 100755 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml create mode 100644 src/main/java/me/whiteship/chapter01/item01/ActionEnum.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/AdvancedSettings.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/App.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/AppConfig.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/Difficulty.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/HelloService.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/HelloServiceFactory.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/ListQuiz.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/Order.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/OrderStatus.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/Product.java create mode 100644 src/main/java/me/whiteship/chapter01/item01/Settings.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/builder/BuilderTest.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/builder/NutritionFacts.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/freeze/FreezeTest.js create mode 100644 src/main/java/me/whiteship/chapter01/item02/freeze/Person.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/Calzone.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/NyPizza.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/Pizza.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/PizzaTest.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/illegalargumentexception/Order.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/javabeans/NutritionFacts.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/telescopingconstructor/NutritionFacts.java create mode 100644 src/main/java/me/whiteship/chapter01/item02/varargs/VarargsSamples.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/enumtype/Elvis.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/enumtype/EnumElvisReflection.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/enumtype/EnumElvisSerialization.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/field/Concert.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/field/Elvis.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/field/ElvisReflection.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/field/ElvisSerialization.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/field/IElvis.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/functionalinterface/DefaultFunctions.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/functionalinterface/MyFunction.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/functionalinterface/UsageOfFunctions.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/methodreference/Person.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/serialization/Book.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/serialization/SerializationExample.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/staticfactory/Concert.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/staticfactory/Elvis.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/staticfactory/MetaElvis.java create mode 100644 src/main/java/me/whiteship/chapter01/item03/staticfactory/Singer.java create mode 100644 src/main/java/me/whiteship/chapter01/item04/DefaultUtilityClass.java create mode 100644 src/main/java/me/whiteship/chapter01/item04/UtilityClass.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/DefaultDictionary.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/Dictionary.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/MockDictionary.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/dependencyinjection/DictionaryFactory.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/dependencyinjection/SpellChecker.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/factorymethod/DefaultDictionaryFactory.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/factorymethod/DictionaryFactory.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/factorymethod/MockDictionaryFactory.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/factorymethod/SpellChecker.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/package-info.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/singleton/SpellChecker.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/springioc/App.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/springioc/AppConfig.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/springioc/SpellChecker.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/springioc/SpringDictionary.java create mode 100644 src/main/java/me/whiteship/chapter01/item05/staticutils/SpellChecker.java create mode 100644 src/main/java/me/whiteship/chapter01/item06/Client.java create mode 100644 src/main/java/me/whiteship/chapter01/item06/Deprecation.java create mode 100644 src/main/java/me/whiteship/chapter01/item06/RegularExpression.java create mode 100644 src/main/java/me/whiteship/chapter01/item06/RomanNumerals.java create mode 100644 src/main/java/me/whiteship/chapter01/item06/Strings.java create mode 100644 src/main/java/me/whiteship/chapter01/item06/Sum.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/cache/CacheKey.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/cache/Post.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/cache/PostRepository.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/executor/ExecutorsExample.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/listener/ChatRoom.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/listener/User.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/optional/Channel.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/optional/MemberShip.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/reference/BigObject.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/reference/BigObjectReference.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/reference/PhantomReferenceExample.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/reference/SoftReferenceExample.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/reference/WeakReferenceExample.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/stack/EmptyStackException.java create mode 100644 src/main/java/me/whiteship/chapter01/item07/stack/Stack.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/autoclosable/App.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/autoclosable/AutoClosableIsGood.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/cleaner/BigObject.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/cleaner/CleanerIsNotGood.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Adult.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Room.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Teenager.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/finalizer/App.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/finalizer/FinalizerIsBad.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/finalizer_attack/Account.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/finalizer_attack/BrokenAccount.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/outerclass/LambdaExample.java create mode 100644 src/main/java/me/whiteship/chapter01/item08/outerclass/OuterClass.java create mode 100644 src/main/java/me/whiteship/chapter01/item09/puzzler/Copy.java create mode 100644 src/main/java/me/whiteship/chapter01/item09/suppress/BadBufferedReader.java create mode 100644 src/main/java/me/whiteship/chapter01/item09/suppress/TopLine.java create mode 100644 src/main/java/me/whiteship/chapter01/item09/tryfinally/Copy.java create mode 100644 src/main/java/me/whiteship/chapter01/item09/tryfinally/TopLine.java create mode 100644 src/main/java/me/whiteship/chapter01/item09/trywithresources/Copy.java create mode 100644 src/main/java/me/whiteship/chapter01/item09/trywithresources/TopLine.java create mode 100644 src/main/java/me/whiteship/chapter01/item09/trywithresources/TopLineWithDefault.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/CaseInsensitiveString.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/Color.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/EqualsInJava.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/PhoneNumber.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/Point.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/autovalue/AutoValueTest.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/autovalue/Point.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/composition/ColorPoint.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/inheritance/ColorPoint.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/inheritance/CounterPoint.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/inheritance/CounterPointTest.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/inheritance/SmellPoint.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/inheritance/SmellPointTest.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/lombok/LombokTest.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/lombok/Point.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/record/Point.java create mode 100644 src/main/java/me/whiteship/chapter02/item10/record/PointTest.java create mode 100644 src/main/java/me/whiteship/chapter02/item11/guava/PhoneNumber.java create mode 100644 src/main/java/me/whiteship/chapter02/item11/hashcode/PhoneNumber.java create mode 100644 src/main/java/me/whiteship/chapter02/item11/hashtable/HashMapTest.java create mode 100644 src/main/java/me/whiteship/chapter02/item11/package-info.java create mode 100644 src/main/java/me/whiteship/chapter02/item12/PhoneNumber.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/EmptyStackException.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/HashTable.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/PhoneNumber.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/Stack.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/clone_use_constructor/Item.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/clone_use_constructor/SubItem.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/copy_constructor/HashSetExample.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/exception/MyApp.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/exception/MyException.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/inheritance/Shape.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/inheritance/Square.java create mode 100644 src/main/java/me/whiteship/chapter02/item13/treeset/TreeSetExample.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/CaseInsensitiveString.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/CompareToConvention.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/PhoneNumber.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/WordList.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/composition/NamedPoint.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/composition/Point.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/decimal/DecimalIsNotCorrect.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/decimal/IntOverflow.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/interitance/NamedPoint.java create mode 100644 src/main/java/me/whiteship/chapter02/item14/interitance/Point.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/me/whiteship/chapter01/item03/field/ConcertTest.java create mode 100644 src/test/java/me/whiteship/chapter01/item03/field/MockElvis.java create mode 100644 src/test/java/me/whiteship/chapter01/item05/dependencyinjection/SpellCheckerTest.java create mode 100644 src/test/java/me/whiteship/chapter01/item05/staticutils/SpellCheckerTest.java create mode 100644 src/test/java/me/whiteship/chapter01/item07/cache/PostRepositoryTest.java create mode 100644 src/test/java/me/whiteship/chapter01/item07/listener/ChatRoomTest.java create mode 100644 src/test/java/me/whiteship/chapter01/item07/optional/ChannelTest.java create mode 100644 src/test/java/me/whiteship/chapter01/item08/finalizer_attack/AccountTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..c1dd12f17644411d6e840bd5a10c6ecda0175f18 GIT binary patch literal 58727 zcmb5W18`>1vNjyPv28mO+cqb*Z6_1kwr$(?#I}=(ZGUs`Jr}3`|DLbDUA3!L?dtC8 zUiH*ktDo+@6r@4HP=SCTA%WmZqm^Ro`Ls)bfPkcdfq?#g1(Fq27W^S8Cq^$TC?_c< zs-#ROD;6C)1wFuk7<3)nGuR^#!H;n&3*IjzXg+s8Z_S!!E0jUq(`}Itt=YdYa5Z_s z&e>2={87knpF*PKNzU;lsbk#P(l^WBvb$yEz)z+nYH43pKodrDkMp@h?;n{;K}hl>Fb^ zqx}C0|D7kg|Cj~3f7hn_zkAE}|6t|cZT|S5Hvb#3nc~C14u5UI{6#F<|FkJ0svs&S zA}S{=DXLT*BM1$`2rK%`D@vEw9l9%*=92X_2g?Fwfi=6Zfpr7+<~sgP#Bav+Df2ts zwtu~70zhqV?mrzM)}r7mMS`Hk_)NrI5K%CTtQtDxqw5iv5F0!ksIon{qqpPVnU?ds zN$|Vm{MHKEReUy>1kVfT-$3))Js0p2W_LFy3cjjZ7za0R zPdBH>y&pb0vr1|ckDpt2p$IQhwnPs5G*^b-y}sg4W!ALn}a`pY0JIa$H0$eV2T8WjWD= zWaENacQhlTyK4O!+aOXBurVR2k$eb8HVTCxy-bcHlZ4Xr!`juLAL#?t6|Ba!g9G4I zSwIt2Lla>C?C4wAZ8cKsZl9-Yd3kqE`%!5HlGdJJaFw0mu#--&**L-i|BcIdc3B$;0FC;FbE-dunVZ; zdIQ=tPKH4iJQQ=$5BeEMLov_Hn>gXib|9nOr}>eZt@B4W^m~>Zp#xhn1dax+?hS!AchWJ4makWZs@dQUeXQ zsI2+425_{X@t2KN zIbqec#)Jg5==VY3^YBeJ2B+%~^Y8|;F!mE8d(`UgNl2B9o>Ir5)qbBr)a?f%nrP zQyW(>FYPZjCVKDOU;Bw#PqPF1CCvp)dGdA&57a5hD&*vIc)jA)Z-!y5pS{5W6%#prH16zgD8s zexvpF#a|=*acp>L^lZ(PT)GiA8BJL-9!r8S$ZvXRKMVtiGe`+!@O%j<1!@msc177U zTDy>WOZu)W5anPrweQyjIu3IJC|ngdjZofGbdW&oj^DJlC7$;|xafB45evT|WBgGf-b|9y0J`fe0W-vw6xh}` z=(Tnq(-K0O{;VUcKe2y63{HXc+`R_#HLwnZ0rzWO*b#VeSuC4NG!H_ApCypbt1qx( z6y7Q$5(JOpQ&pTkc^0f}A0Kq*?;g9lEfzeE?5e2MBNZB)^8W1)YgdjsVyN+I9EZlh z3l}*}*)cFl=dOq|DvF=!ui$V%XhGQ%bDn3PK9 zV%{Y|VkAdt^d9~y4laGDqSwLd@pOnS&^@sI7}YTIb@El1&^_sq+{yAGf0|rq5TMp# z6d~;uAZ(fY3(eH=+rcbItl2=u6mf|P{lD4kiRCv;>GtFaHR3gim?WU9RjHmFZLm+m z+j<}_exaOQ1a}=K#voc~En+Mk_<(L!?1e#Uay~|H5q)LjD*yE6xFYQ-Wx{^iH1@pP zC0De#D6I26&W{;J40sZB!=%{c?XdO?YQvnTMA3TwfhAm@bvkX*(x?JTs*dFDv^=2X z284}AK)1nRn+8(Q2P?f)e>0~;NUI9%p%fnv1wBVpoXL+9OE`Vv1Y7=+nub$o7AN>y zB?R(^G8PYcMk4bxe7XItq@48QqWKb8fa*i9-N)=wdU-Q^=}!nFgTr_uT=Z=9pq z`{7!$U|+fnXFcsJ4GNm3JQQCN+G85k$)ZLhF{NbIy{REj84}Zt;0fe#>MARW)AoSb zrBpwF37ZVBMd>wZn_hAadI*xu8)Y#`aMbwRIA2n^-OS~M58_@j?#P1|PXJ1XBC9{4 zT^8*|xu<@(JlSOT*ILrVGr+7$nZN`Z3GxJJO@nY&mHsv^^duAh*lCu5q+S6zWA+`- z%^*y#)O7ko_RwGJl;bcEpP03FOrhlLWs`V_OUCrR-g>NJz*pN|itmN6O@Hw05Zq;Xtif%+sp4Py0{<7<^c zeoHHhRq>2EtYy9~2dZywm&OSk`u2ECWh6dJY?;fT-3-$U`!c(o$&hhPC%$~fT&bw3 zyj+8aXD;G!p*>BC6rpvx#6!|Qaic;KEv5>`Y+R(6F^1eIeYG6d1q3D3OL{7%7iw3R zwO)W7gMh27ASSB>-=OfP(YrKqBTNFv4hL@Im~~ombbSu44p~VoH$H-6+L_JW>Amkl zhDU~|r77?raaxD!-c$Ta?WAAi{w3T}YV=+S?1HQGC0+{Bny_^b+4Jum}oW4c=$ z#?D<}Ds{#d5v`L`${Pee;W84X*osNQ96xsKp^EAzuUh9#&zDX=eqdAp$UY)EGrkU% z(6m35n=46B$TNnejNSlih_!<)Iu@K!PW5S@Ya^0OK+EMWM=1w=GUKW^(r59U%i?d zzbo?|V4tDWGHHsrAQ}}ma#<`9r=M8%XF#%a=@Hn(p3wFBlkZ2L@8=*@J-^zuyF0aN zzJ7f!Jf8I+^6Tt$e+IIh zb80@?7y#Iz3w-0VEjgbHurqI>$qj<@n916)&O340!_5W9DtwR)P5mk6v2ljyK*DG5 zYjzE~m`>tq8HYXl%1JJ%e-%BqV4kRdPUZB1Cm$BQZr(fzp_@rn_W+;GwI$?L2Y4;b z)}c5D$#LT}2W8Si<`EHKIa_X+>+2PF(C*u~F=8E!jL(=IdQxY40%|( zoNg2Z&Aob@LEui-lJ#@)Ts)tE0_!*3{Uk)r{;-IZpX`N4mZX`#E|A;viQWImB6flI z?M_|xHCXV$5LOY-!U1_O1k;OWa=EchwlDCK4xHwBW2jE-6&%}og+9NILu${v10Z^Z#* zap|)B9a-AMU~>$r)3&|dQuP#MA$jnw54w*Ax~*_$iikp+j^OR8I5Fo<_UR#B-c>$? zeg)=;w^sGeAMi<3RGDRj$jA30Qq$e|zf2z;JyQ}tkU)ZI_k6tY%(`#AvL)p)iYXUy z5W9Su3NJ8mVyy)WqzFSk&vZM!;kUh8dVeA-myqcV%;xUne`PbHCPpvH?br`U2Y&dM zV!nJ!^n%`!H&!QSlpzLWnZpgi;#P0OAleH+<CfLa?&o|kyw1}W%6Pij zp$Vv5=;Z0LFN|j9i&9>zqX>*VnV3h#>n!2L?5gO6HJS3~kpy5G zYAVPMaB-FJOk3@OrxL(*-O~OB9^d{!G0K>wlzXuBm*$&%p1O#6SQ*?Q0CETLQ->XpfkW7< zj&Nep(}eAH1u$wWFvLV*lA{JOltP_%xKXC*a8DB&;{fD&2bATy>rC^kFY+$hFS7us;Y) zy_H?cv9XTHYz<4C<0b`WKC#{nJ15{F=oaq3x5}sYApT?Po+(Cmmo#dHZFO^{M#d~d znRT=TFATGVO%z_FNG-@G;9az|udZ>t@5l+A-K)BUWFn_|T#K3=d3EXRNqHyi#>;hX z*JQ`pT3#&tH>25laFlL6Rllu(seA*OboEd%rxMtz3@5v-+{qDP9&BcoS$2fgjgvp$ zc8!3=p0p@Ee1$u{Gg}Kkxg@M*qgZfYLlnD88{uwG1T?zxCbBR+x(RK$JB(eWJH#~; zZoY6L+esVRV?-*QmRCG}h`rB*Lv=uE%URF@+#l-g!Artx>Y9D;&G=jY2n2`J z{6-J%WX~Glx*QBmOOJ(RDRIzhfk&ibsm1t&&7aU{1P3U0uM%F2zJb4~50uby_ng+# zN)O9lK=dkJpxsUo7u8|e`Y~mmbxOTDn0i!i;d;ml#orN(Lc=j+n422NoSnlH6?0<0?th-qB7u}`5My%#?ES}>@RldOQz}WILz<$+cN~&ET zwUI01HCB((TyU$Ej8bxsE8oLmT-c7gA1Js?Iq`QMzIHV|)v)n2 zT_L(9x5%8*wU(C`VapaHoicWcm|0X@9TiNtbc|<4N6_H1F6&qgEEj=vjegFt;hC7- zLG7_=vedRFZ6Chbw!{#EpAlM?-sc#pc<~j#537n)M%RT)|L}y(ggi_-SLpsE3qi3V z=EEASxc>a{Su)jXcRS41Z@Mxk&0B7B<(?Izt5wpyyIBO|-M}ex8BhbIgi*X4 zDZ+Yk1<6&=PoZ=U-!9`!?sBVpYF#Y!JK<`fx}bXN651o0VVaW;t6ASVF@gq-mIDV_)?F^>rq1XX0NYy~(G=I6x%Fi5C2rMtvs z%P`g2>0{xLUy~#ye)%QAz^NkD5GUyPYl}K#;e-~UQ96`I$U0D!sMdQ>;%+c0h>k*Y z)sD1mi_@|rZnQ+zbWq~QxFlBQXj8WEY7NKaOYjUxAkGB8S#;l@b^C?;twRKl=mt0< zazifrBs`(q7_r14u1ZS`66VmsLpV>b5U!ktX>g4Nq~VPq6`%`3iCdr(>nS~uxxylU z>h(2p$XPJVh9BDpRLLzTDlNdp+oq8sOUlJ#{6boG`k)bwnsw5iy@#d{f_De-I|}vx6evw;ch97=;kLvM)-DBGwl6%fA%JItoMeyqjCR*_5Q70yd!KN zh=>ek8>f#~^6CJR0DXp0;7ifZjjSGBn}Cl{HeX!$iXMbtAU$F+;`%A<3TqbN#PCM& z&ueq$cB%pu2oMm_-@*aYzgn9`OiT@2ter*d+-$Aw42(@2Ng4mKG%M-IqX?q%3R|_( zN|&n$e1L#Ev=YMX5F53!O%))qDG3D(0rsOHblk;9ghWyqEOpg)mC$OduqpHAuIxr_>*|zy+|=EmOFn zFM+Ni%@CymLS-3vRWn=rVk?oZEz0V#y356IE6HR5#>7EigxZ05=cA|4<_tC8jyBJ| zgg!^kNwP7S^ooIj6riI9x`jFeQfRr4JCPumr<82M zto$j^Qb~MPmJ-|*2u{o7?yI8BI``zDaOCg2tG_5X;w<|uj5%oDthnLx-l4l)fmUGx z6N^jR|DC);yLi4q-ztTkf>*U$@2^w5(lhxu=OC|=WuTTp^!?2Nn27R`2FY_ zLHY-zFS}r+4|XyZw9b0D3)DmS!Gr+-LSdI}m{@-gL%^8CFSIYL?UZaCVd)2VI3|ay zwue39zshVrB+s2lp*};!gm<79@0HkjhgF^>`UhoR9Mi`aI#V#fI@x&1K3f&^8kaq% zkHVg$CTBoaGqEjrL)k*Y!rtiD2iQLYZ%|B}oBl8GHvR%n>HiIQN*+$mCN>I=c7H2N z&K4$4e@E^ff-cVHCbrHNMh4Dy|2Q;M{{xu|DYjeaRh2FK5QK!bG_K`kbBk$l$S4UF zq?F-%7UrX_Q?9M)a#WvcZ^R-fzJB5IFP>3uEoeCAAhN5W-ELRB&zsCnWY6#E?!)E56Pe+bxHjGF6;R9Hps)+t092-bf4 z_Wieg+0u5JL++k)#i0r?l`9*k)3ZlHOeMJ1DTdx9E1J2@BtdD3qX;&S_wMExOGv$T zl^T%oxb+)vq6vJvR`8{+YOsc@8}wSXpoK%v0k@8X*04Se3<8f)rE|fRXAoT!$6MdrKSuzeK@L*yug?MQs8oTbofqW)Df# zC2J3irHAaX_e~SGlBoRhEW`W6Z}&YX|5IMfzskAt{B*m z*w=3i!;x5Gfgc~>y9fPXFAPMhO@Si}SQESjh`P|dlV5HPRo7j(hV=$o8UMIT7~7+k z*@Sd>f%#{ARweJYhQs~ECpHie!~YXL|FJA;KS4m|CKFnT{fN`Ws>N?CcV@(>7WMPYN} z1}Wg+XU2(Yjpq7PJ|aSn;THEZ{4s8*@N!dz&bjys_Zk7%HiD+56;cF26`-a zEIo!B(T|L*uMXUvqJs&54`^@sUMtH-i~rOM9%$xGXTpmow$DxI>E5!csP zAHe|);0w%`I<==_Zw9t$e}?R+lIu%|`coRum(1p~*+20mBc?Z=$+z<0n&qS0-}|L4 zrgq|(U*eB%l3nfC=U1Y?(Tf@0x8bhdtsU2w&Y-WvyzkiyJ>GZqUP6c+<_p0`ZOnIK z#a~ynuzRWxO6c;S@*}B1pTjLJQHi(+EuE2;gG*p^Fq%6UoE1x95(^BY$H$$soSf=vpJ)_3E zp&$l=SiNaeoNLAK8x%XaHp3-So@F7 z3NMRRa@%k+Z$a%yb25ud&>Cdcb<+}n>=jZ`91)a z{wcA(j$%z#RoyB|&Z+B4%7Pe*No`pAX0Y;Ju4$wvJE{VF*Qej8C}uVF=xFpG^rY6Y+9mcz$T9^x(VP3uY>G3Zt&eU{pF*Bu<4j9MPbi4NMC=Z$kS6DMW9yN#vhM&1gd1t}8m(*YY9 zh2@s)$1p4yYT`~lYmU>>wKu+DhlnI1#Xn4(Rnv_qidPQHW=w3ZU!w3(@jO*f;4;h? zMH0!08(4=lT}#QA=eR(ZtW1=~llQij7)L6n#?5iY_p>|_mLalXYRH!x#Y?KHyzPB^ z6P3YRD}{ou%9T%|nOpP_??P;Rmra7$Q*Jz-f?42PF_y>d)+0Q^)o5h8@7S=je}xG# z2_?AdFP^t{IZHWK)9+EE_aPtTBahhUcWIQ7Awz?NK)ck2n-a$gplnd4OKbJ;;tvIu zH4vAexlK2f22gTALq5PZ&vfFqqERVT{G_d`X)eGI%+?5k6lRiHoo*Vc?ie6dx75_t z6hmd#0?OB9*OKD7A~P$e-TTv3^aCdZys6@`vq%Vi_D8>=`t&q9`Jn1=M#ktSC>SO3 z1V?vuIlQs6+{aHDHL?BB&3baSv;y#07}(xll9vs9K_vs2f9gC9Biy+9DxS77=)c z6dMbuokO-L*Te5JUSO$MmhIuFJRGR&9cDf)@y5OQu&Q$h@SW-yU&XQd9;_x;l z<`{S&Hnl!5U@%I~5p)BZspK894y7kVQE7&?t7Z|OOlnrCkvEf7$J5dR?0;Jt6oANc zMnb_Xjky|2ID#fhIB2hs-48Er>*M?56YFnjC)ixiCes%fgT?C|1tQupZ0Jon>yr|j z6M66rC(=;vw^orAMk!I1z|k}1Ox9qOILGJFxU*ZrMSfCe?)wByP=U73z+@Pfbcndc=VzYvSUnUy z+-B+_n`=f>kS8QBPwk+aD()=#IqkdxHPQMJ93{JGhP=48oRkmJyQ@i$pk(L&(p6<0 zC9ZEdO*i+t`;%(Ctae(SjV<@i%r5aune9)T4{hdzv33Uo9*K=V18S$6VVm^wgEteF za0zCLO(9~!U9_z@Qrh&rS|L0xG}RWoE1jXiEsrTgIF4qf#{0rl zE}|NGrvYLMtoORV&FWaFadDNCjMt|U8ba8|z&3tvd)s7KQ!Od*Kqe(48&C7=V;?`SQV)Qc?6L^k_vNUPbJ>>!5J?sDYm5kR&h_RZk)MfZ1 znOpQ|T;Me(%mdBJR$sbEmp3!HKDDSmMDnVpeo{S13l#9e6OImR$UPzjd-eCwmMwyT zm5~g6DIbY<_!8;xEUHdT(r_OQ<6QCE9Jy|QLoS>d(B zW6GRzX)~&Mx}})ITysFzl5_6JM*~ciBfVP(WF_r zY>z4gw&AxB%UV3Y{Y6z*t*o!p@~#u3X_t{Q9Us8ar8_9?N% zN&M~6y%2R(mAZ~@Tg1Oapt?vDr&fHuJ=V$wXstq|)eIG_4lB#@eU>fniJh zwJY<8yH5(+SSQ=$Y=-$2f$@^Ak#~kaR^NYFsi{XGlFCvK(eu{S$J(owIv17|p-%0O zL-@NyUg!rx0$Uh~JIeMX6JJE>*t<7vS9ev#^{AGyc;uio_-Je1?u#mA8+JVczhA2( zhD!koe;9$`Qgaxlcly4rdQ1VlmEHUhHe9TwduB+hm3wH2o27edh?|vrY{=;1Doy4& zIhP)IDd91@{`QQqVya(ASth4}6OY z-9BQj2d-%+-N7jO8!$QPq%o$9Fy8ja{4WT$gRP+b=Q1I48g-g|iLNjbhYtoNiR*d- z{sB}~8j*6*C3eM8JQj5Jn?mD#Gd*CrVEIDicLJ-4gBqUwLA-bp58UXko;M|ql+i5` zym-&U5BIS9@iPg#fFbuXCHrprSQKRU0#@yd%qrX1hhs*85R}~hahfFDq=e@bX))mf zWH%mXxMx|h5YhrTy;P_Xi_IDH*m6TYv>|hPX*_-XTW0G9iu!PqonQneKKaCVvvF^% zgBMDpN7!N?|G5t`v{neLaCFB{OyIl>qJQ_^0MJXQ zY2%-si~ej?F^%ytIIHU(pqT+3d+|IQ{ss#!c91R{2l*00e3ry!ha|XIsR%!q=E^Fal`6Oxu`K0fmPM?P6ZgzH7|TVQhl;l2 z)2w0L9CsN-(adU5YsuUw19OY_X69-!=7MIJ^(rUNr@#9l6aB8isAL^M{n2oD0FAHk97;X* z-INjZ5li`a|NYNt9gL2WbKT!`?%?lB^)J)9|025nBcBtEmWBRXQwi21EGg8>!tU>6Wf}S3p!>7vHNFSQR zgC>pb^&OHhRQD~7Q|gh5lV)F6i++k4Hp_F2L2WrcxH&@wK}QgVDg+y~o0gZ=$j&^W zz1aP8*cvnEJ#ffCK!Kz{K>yYW`@fc8ByF9X4XmyIv+h!?4&$YKl*~`ToalM{=Z_#^ zUs<1Do+PA*XaH;&0GW^tDjrctWKPmCF-qo7jGL)MK=XP*vt@O4wN1Y!8o`{DN|Rh) znK?nvyU&`ATc@U*l}=@+D*@l^gYOj&6SE|$n{UvyPwaiRQ_ua2?{Vfa|E~uqV$BhH z^QNqA*9F@*1dA`FLbnq;=+9KC@9Mel*>6i_@oVab95LHpTE)*t@BS>}tZ#9A^X7nP z3mIo+6TpvS$peMe@&=g5EQF9Mi9*W@Q`sYs=% z`J{3llzn$q;2G1{N!-#oTfQDY`8>C|n=Fu=iTk443Ld>>^fIr4-!R3U5_^ftd>VU> zij_ix{`V$I#k6!Oy2-z#QFSZkEPrXWsYyFURAo`Kl$LkN>@A?_);LE0rZIkmjb6T$ zvhc#L-Cv^4Ex*AIo=KQn!)A4;7K`pu-E+atrm@Cpmpl3e>)t(yo4gGOX18pL#xceU zbVB`#5_@(k{4LAygT1m#@(7*7f5zqB)HWH#TCrVLd9}j6Q>?p7HX{avFSb?Msb>Jg z9Q9DChze~0Psl!h0E6mcWh?ky! z$p#@LxUe(TR5sW2tMb#pS1ng@>w3o|r~-o4m&00p$wiWQ5Sh-vx2cv5nemM~Fl1Pn z@3ALEM#_3h4-XQ&z$#6X&r~U-&ge+HK6$)-`hqPj0tb|+kaKy*LS5@a9aSk!=WAEB z7cI`gaUSauMkEbg?nl0$44TYIwTngwzvUu0v0_OhpV;%$5Qgg&)WZm^FN=PNstTzW z5<}$*L;zrw>a$bG5r`q?DRc%V$RwwnGIe?m&(9mClc}9i#aHUKPLdt96(pMxt5u`F zsVoku+IC|TC;_C5rEU!}Gu*`2zKnDQ`WtOc3i#v}_9p>fW{L4(`pY;?uq z$`&LvOMMbLsPDYP*x|AVrmCRaI$UB?QoO(7mlBcHC};gA=!meK)IsI~PL0y1&{Dfm6! zxIajDc1$a0s>QG%WID%>A#`iA+J8HaAGsH z+1JH=+eX5F(AjmZGk|`7}Gpl#jvD6_Z!&{*kn@WkECV-~Ja@tmSR|e_L@9?N9 z3hyyry*D0!XyQh_V=8-SnJco#P{XBd1+7<5S3FA)2dFlkJY!1OO&M7z9uO?$#hp8K z><}uQS-^-B;u7Z^QD!7#V;QFmx0m%{^xtl3ZvPyZdi;^O&c;sNC4CHxzvvOB8&uHl zBN;-lu+P=jNn`2k$=vE0JzL{v67psMe_cb$LsmVfxA?yG z^q7lR00E@Ud3)mBPnT0KM~pwzZiBREupva^PE3~e zBgQ9oh@kcTk2)px3Hv^VzTtMzCG?*X(TDZ1MJ6zx{v- z;$oo46L#QNjk*1przHSQn~Ba#>3BG8`L)xla=P{Ql8aZ!A^Z6rPv%&@SnTI7FhdzT z-x7FR0{9HZg8Bd(puRlmXB(tB?&pxM&<=cA-;RT5}8rI%~CSUsR^{Dr%I2WAQghoqE5 zeQ874(T`vBC+r2Mi(w`h|d zA4x%EfH35I?h933@ic#u`b+%b+T?h=<}m@x_~!>o35p|cvIkkw07W=Ny7YcgssA_^ z|KJQrnu||Nu9@b|xC#C5?8Pin=q|UB?`CTw&AW0b)lKxZVYrBw+whPwZJCl}G&w9r zr7qsqm>f2u_6F@FhZU0%1Ioc3X7bMP%by_Z?hds`Q+&3P9-_AX+3CZ=@n!y7udAV2 zp{GT6;VL4-#t0l_h~?J^;trk1kxNAn8jdoaqgM2+mL&?tVy{I)e`HT9#Tr}HKnAfO zAJZ82j0+49)E0+=x%#1_D;sKu#W>~5HZV6AnZfC`v#unnm=hLTtGWz+21|p)uV+0= zDOyrLYI2^g8m3wtm-=pf^6N4ebLJbV%x`J8yd1!3Avqgg6|ar z=EM0KdG6a2L4YK~_kgr6w5OA;dvw0WPFhMF7`I5vD}#giMbMzRotEs&-q z^ji&t1A?l%UJezWv?>ijh|$1^UCJYXJwLX#IH}_1K@sAR!*q@j(({4#DfT|nj}p7M zFBU=FwOSI=xng>2lYo5*J9K3yZPwv(=7kbl8Xv0biOba>vik>6!sfwnH(pglq1mD-GrQi8H*AmfY*J7&;hny2F zupR}4@kzq+K*BE%5$iX5nQzayWTCLJ^xTam-EEIH-L2;huPSy;32KLb>>4 z#l$W^Sx7Q5j+Sy*E;1eSQQuHHWOT;1#LjoYpL!-{7W3SP4*MXf z<~>V7^&sY|9XSw`B<^9fTGQLPEtj=;<#x^=;O9f2{oR+{Ef^oZ z@N>P$>mypv%_#=lBSIr_5sn zBF-F_WgYS81vyW6$M;D_PoE&%OkNV1&-q+qgg~`A7s}>S`}cn#E$2m z%aeUXwNA(^3tP=;y5%pk#5Yz&H#AD`Jph-xjvZm_3KZ|J>_NR@croB^RUT~K;Exu5%wC}1D4nov3+@b8 zKyU5jYuQ*ZpTK23xXzpN51kB+r*ktnQJ7kee-gP+Ij0J_#rFTS4Gux;pkVB;n(c=6 zMks#)ZuXUcnN>UKDJ-IP-u2de1-AKdHxRZDUGkp)0Q#U$EPKlSLQSlnq)OsCour)+ zIXh@3d!ImInH7VrmR>p8p4%n;Tf6l2jx1qjJu>e3kf5aTzU)&910nXa-g0xn$tFa& z2qZ7UAl*@5o=PAh`6L${6S-0?pe3thPB4pahffb$#nL8ncN(Nyos`}r{%{g64Ji^= zK8BIywT0-g4VrhTt}n~Y;3?FGL74h?EG*QfQy0A8u>BtXuI{C-BYu*$o^}U1)z;8d zVN(ssw?oCbebREPD~I$-t7}`_5{{<0d10So7Pc2%EREdpMWIJI&$|rq<0!LL+BQM4 zn7)cq=qy|8YzdO(?NOsVRk{rW)@e7g^S~r^SCawzq3kj#u(5@C!PKCK0cCy zT@Tey2IeDYafA2~1{gyvaIT^a-Yo9kx!W#P-k6DfasKEgFji`hkzrmJ#JU^Yb%Nc~ zc)+cIfTBA#N0moyxZ~K!`^<>*Nzv-cjOKR(kUa4AkAG#vtWpaD=!Ku&;(D#(>$&~B zI?V}e8@p%s(G|8L+B)&xE<({g^M`#TwqdB=+oP|5pF3Z8u>VA!=w6k)zc6w2=?Q2` zYCjX|)fRKI1gNj{-8ymwDOI5Mx8oNp2JJHG3dGJGg!vK>$ji?n>5qG)`6lEfc&0uV z)te%G&Q1rN;+7EPr-n8LpNz6C6N0*v{_iIbta7OTukSY zt5r@sO!)rjh0aAmShx zd3=DJ3c(pJXGXzIh?#RR_*krI1q)H$FJ#dwIvz);mn;w6Rlw+>LEq4CN6pP4AI;!Y zk-sQ?O=i1Mp5lZX3yka>p+XCraM+a!1)`F`h^cG>0)f0OApGe(^cz-WoOno-Y(EeB zVBy3=Yj}ak7OBj~V259{&B`~tbJCxeVy@OEE|ke4O2=TwIvf-=;Xt_l)y`wuQ-9#D z(xD-!k+2KQzr`l$7dLvWf*$c8=#(`40h6d$m6%!SB1JzK+tYQihGQEwR*-!cM>#LD>x_J*w(LZbcvHW@LTjM?RSN z0@Z*4$Bw~Ki3W|JRI-r3aMSepJNv;mo|5yDfqNLHQ55&A>H5>_V9<_R!Ip`7^ylX=D<5 zr40z>BKiC@4{wSUswebDlvprK4SK2!)w4KkfX~jY9!W|xUKGTVn}g@0fG94sSJGV- z9@a~d2gf5s>8XT@`If?Oway5SNZS!L5=jpB8mceuf2Nd%aK2Zt|2FVcg8~7O{VPgI z#?H*_Kl!9!B}MrK1=O!Aw&faUBluA0v#gWVlAmZt;QN7KC<$;;%p`lmn@d(yu9scs zVjomrund9+p!|LWCOoZ`ur5QXPFJtfr_b5%&Ajig2dI6}s&Fy~t^j}()~4WEpAPL= zTj^d;OoZTUf?weuf2m?|R-7 z*C4M6ZhWF(F@2}nsp85rOqt+!+uZz3$ReX#{MP5-r6b`ztXDWl$_mcjFn*{sEx7f*O(ck+ou8_?~a_2Ztsq6qB|SPw26k!tLk{Q~Rz z$(8F1B;zK-#>AmmDC7;;_!;g&CU7a?qiIT=6Ts0cbUNMT6yPRH9~g zS%x{(kxYd=D&GKCkx;N21sU;OI8@4vLg2}L>Lb{Qv`B*O0*j>yJd#`R5ypf^lp<7V zCc|+>fYgvG`ROo>HK+FAqlDm81MS>&?n2E-(;N7}oF>3T9}4^PhY=Gm`9i(DPpuS- zq)>2qz!TmZ6q8;&M?@B;p1uG6RM_Y8zyId{-~XQD_}bXL{Jp7w`)~IR{l5a2?7!Vg zp!OfP4E$Ty_-K3VY!wdGj%2RL%QPHTL)uKfO5Am5<$`5 zHCBtvI~7q-ochU`=NJF*pPx@^IhAk&ZEA>w$%oPGc-}6~ywV~3-0{>*sb=|ruD{y$ ze%@-m`u28vKDaf*_rmN`tzQT>&2ltg-lofR8~c;p;E@`zK!1lkgi?JR0 z+<61+rEupp7F=mB=Ch?HwEjuQm}1KOh=o@ zMbI}0J>5}!koi&v9?!B?4FJR88jvyXR_v{YDm}C)lp@2G2{a{~6V5CwSrp6vHQsfb-U<{SSrQ zhjRbS;qlDTA&TQ2#?M(4xsRXFZ^;3A+_yLw>o-9GJ5sgsauB`LnB-hGo9sJ~tJ`Q>=X7sVmg<=Fcv=JDe*DjP-SK-0mJ7)>I zaLDLOU*I}4@cro&?@C`hH3tiXmN`!(&>@S2bFyAvI&axlSgd=!4IOi#+W;sS>lQ28 zd}q&dew9=x;5l0kK@1y9JgKWMv9!I`*C;((P>8C@JJRGwP5EL;JAPHi5fI|4MqlLU z^4D!~w+OIklt7dx3^!m6Be{Lp55j{5gSGgJz=hlNd@tt_I>UG(GP5s^O{jFU;m~l0 zfd`QdE~0Ym=6+XN*P`i0ogbgAJVjD9#%eBYJGIbDZ4s(f-KRE_>8D1Dv*kgO1~NSn zigx8f+VcA_xS)V-O^qrs&N9(}L!_3HAcegFfzVAntKxmhgOtsb4k6qHOpGWq6Q0RS zZO=EomYL%;nKgmFqxD<68tSGFOEM^u0M(;;2m1#4GvSsz2$jawEJDNWrrCrbO<}g~ zkM6516erswSi_yWuyR}}+h!VY?-F!&Y5Z!Z`tkJz&`8AyQ=-mEXxkQ%abc`V1s>DE zLXd7!Q6C)`7#dmZ4Lm?>CTlyTOslb(wZbi|6|Pl5fFq3y^VIzE4DALm=q$pK>-WM> z@ETsJj5=7=*4 z#Q8(b#+V=~6Gxl?$xq|?@_yQJ2+hAYmuTj0F76c(B8K%;DPhGGWr)cY>SQS>s7%O- zr6Ml8h`}klA=1&wvbFMqk}6fml`4A%G=o@K@8LHifs$)}wD?ix~Id@9-`;?+I7 zOhQN(D)j=^%EHN16(Z3@mMRM5=V)_z(6y^1b?@Bn6m>LUW7}?nupv*6MUVPSjf!Ym zMPo5YoD~t(`-c9w)tV%RX*mYjAn;5MIsD?0L&NQ#IY`9k5}Fr#5{CeTr)O|C2fRhY z4zq(ltHY2X)P*f?yM#RY75m8c<%{Y?5feq6xvdMWrNuqnR%(o(uo8i|36NaN<#FnT ze-_O*q0DXqR>^*1sAnsz$Ueqe5*AD@Htx?pWR*RP=0#!NjnaE-Gq3oUM~Kc9MO+o6 z7qc6wsBxp7GXx+hwEunnebz!|CX&`z{>loyCFSF-zg za}zec;B1H7rhGMDfn+t9n*wt|C_0-MM~XO*wx7-`@9~-%t?IegrHM(6oVSG^u?q`T zO<+YuVbO2fonR-MCa6@aND4dBy^~awRZcp!&=v+#kH@4jYvxt=)zsHV0;47XjlvDC8M1hSV zm!GB(KGLwSd{F-?dmMAe%W0oxkgDv8ivbs__S{*1U}yQ=tsqHJYI9)jduSKr<63$> zp;a-B^6Hg3OLUPi1UwHnptVSH=_Km$SXrCM2w8P z%F#Boi&CcZ5vAGjR1axw&YNh~Q%)VDYUDZ6f^0;>W7_sZr&QvRWc2v~p^PqkA%m=S zCwFUg2bNM(DaY>=TLmOLaDW&uH;Za?8BAwQo4+Xy4KXX;Z}@D5+}m)U#o?3UF}+(@jr$M4ja*`Y9gy~Y`0 z6Aex1*3ng@2er)@{%E9a3A;cts9cAor=RWt7ege)z=$O3$d5CX&hORZ3htL>jj5qT zW#KGQ;AZ|YbS0fvG~Y)CvVwXnBLJkSps7d~v;cj$D3w=rB9Tx>a&4>(x00yz!o*SOd*M!yIwx;NgqW?(ysFv8XLxs6Lrh8-F`3FO$}V{Avztc4qmZ zoz&YQR`*wWy_^&k-ifJ&N8Qh=E-fH6e}-}0C{h~hYS6L^lP>=pLOmjN-z4eQL27!6 zIe2E}knE;dxIJ_!>Mt|vXj%uGY=I^8(q<4zJy~Q@_^p@JUNiGPr!oUHfL~dw9t7C4I9$7RnG5p9wBpdw^)PtGwLmaQM=KYe z;Dfw@%nquH^nOI6gjP+K@B~0g1+WROmv1sk1tV@SUr>YvK7mxV3$HR4WeQ2&Y-{q~ z4PAR&mPOEsTbo~mRwg&EJE2Dj?TOZPO_@Z|HZX9-6NA!%Pb3h;G3F5J+30BoT8-PU z_kbx`I>&nWEMtfv(-m>LzC}s6q%VdBUVI_GUv3@^6SMkEBeVjWplD5y58LyJhikp4VLHhyf?n%gk0PBr(PZ3 z+V`qF971_d@rCO8p#7*#L0^v$DH>-qB!gy@ut`3 zy3cQ8*t@@{V7F*ti(u{G4i55*xY9Erw3{JZ8T4QPjo5b{n=&z4P^}wxA;x85^fwmD z6mEq9o;kx<5VneT_c-VUqa|zLe+BFgskp_;A)b>&EDmmP7Gx#nU-T@;O+(&&n7ljK zqK7&yV!`FIJAI+SaA6y=-H=tT`zWvBlaed!3X^_Lucc%Q=kuiG%65@@6IeG}e@`ieesOL} zKHBJBso6u&7gzlrpB%_yy<>TFwDI>}Ec|Gieb4=0fGwY|3YGW2Dq46=a1 zVo`Vi%yz+L9)9hbb%FLTC@-G(lODgJ(f&WmSCK9zV3-IV7XI<{2j}ms_Vmb!os)06 zhVIZPZF)hW--kWTCyDVRd2T&t|P&aDrtO5kzXy<*A+5$k7$>4+y%;% znYN-t#1^#}Z6d+ahj*Gzor+@kBD7@f|IGNR$4U=Y0J2#D2)YSxUCtiC1weJg zLp0Q&JFrt|In8!~1?fY0?=fPyaqPy$iQXJDhHP>N%B42Yck`Qz-OM_~GMuWow)>=Q z0pCCC7d0Z^Ipx29`}P3;?b{dO?7z0e{L|O*Z}nxi>X|RL8XAw$1eOLKd5j@f{RQ~Y zG?7$`hy@s7IoRF2@KA%2ZM6{ru9T5Gj)iDCz};VvlG$WuT+>_wCTS~J6`I9D{nsrU z2;X#OyopBgo778Q>D%_E>rMN~Po~d5H<`8|Zcv}F`xL5~NCVLX4Wkg007HhMgj9Pa z94$km3A+F&LzOJlpeFR*j+Y%M!Qm42ziH~cKM&3b;15s)ycD@3_tL-dk{+xP@J7#o z-)bYa-gd2esfy<&-nrj>1{1^_L>j&(MA1#WNPg3UD?reL*}V{ag{b!uT755x>mfbZ z0PzwF+kx91`qqOn`1>xw@801XAJlH>{`~|pyi6J;3s=cTOfelA&K5HX#gBp6s<|r5 zjSSj+CU*-TulqlnlP`}?)JkJ_7fg){;bRlXf+&^e8CWwFqGY@SZ=%NmLCXpYb+}7* z$4k}%iFUi^kBdeJg^kHt)f~<;Ovlz!9frq20cIj>2eIcG(dh57ry;^E^2T)E_8#;_9iJT>4sdCB_db|zO?Z^*lBN zNCs~f+Jkx%EUgkN2-xFF?B%TMr4#)%wq?-~+Nh;g9=n3tM>i5ZcH&nkVcPXgYRjG@ zf(Y7WN@hGV7o0bjx_2@bthJ`hjXXpfaes_(lWIw!(QK_nkyqj?{j#uFKpNVpV@h?7_WC3~&%)xHR1kKo`Cypj15#%0m z-o0GXem63g^|IltM?eZV=b+Z2e8&Z1%{0;*zmFc62mNqLTy$Y_c|9HiH0l>K z+mAx7DVYoHhXfdCE8Bs@j=t0f*uM++Idd25BgIm`Ad;I_{$mO?W%=JF82blr8rl>yMk6?pM z^tMluJ-ckG_}OkxP91t2o>CQ_O8^VZn$s$M_APWIXBGBq0Lt^YrTD5(Vwe2ta4y#DEYa(W~=eLOy7rD^%Vd$kL27M)MSpwgoP3P{ z!yS$zc|uP{yzaIqCwE!AfYNS;KW|OdP1Q%!LZviA0e^WDsIS5#= z!B{TW)VB)VHg{LoS#W7i6W>*sFz!qr^YS0t2kh90y=Je5{p>8)~D@dLS@QM(F# zIp{6M*#(@?tsu1Rq-Mdq+eV}ibRSpv#976C_5xlI`$#1tN`sK1?)5M+sj=OXG6dNu zV1K{y>!i0&9w8O{a>`IA#mo(3a zf*+Q=&HW7&(nX8~C1tiHZj%>;asBEp$p_Q!@Y0T8R~OuPEy3Lq@^t$8=~(FhPVmJJ z#VF8`(fNzK-b%Iin7|cxWP0xr*M&zoz|fCx@=Y!-0j_~cuxsDHHpmSo)qOalZ$bRl z2F$j0k3llJ$>28HH3l_W(KjF^!@LwtLej_b9;i;{ku2x+&WA@jKTO0ad71@_Yta!{ z2oqhO4zaU433LK371>E{bZ?+3kLZ9WQ2+3PTZAP90%P13Yy3lr3mhmy|>eN6(SHs1C%Q39p)YsUr7(kuaoIJGJhXV-PyG zjnxhcAC;fqY@6;MWWBnRK6ocG`%T&0&*k95#yK7DFtZV?;cy;!RD_*YJjsb6Q`$;K zy)&X{P`*5xEgjTQ9r=oh0|>Z_yeFm?ev!p z7q;JA4mtu@qa39v%6i)Z4%qwdxcHuOMO;a1wFMP_290FqH1OsmCG{ zq^afYrz2BQyQ0*JGE}1h!W9fKgk$b!)|!%q(1x?5=}PpmZQ$e;2EB*k4%+&+u;(E* z2n@=9HsqMv;4>Nn^2v&@4T-YTkd`TdWU^U*;sA5|r7TjZGnLY*xC=_K-GmDfkWEGC z;oN&!c1xB-<4J7=9 zJ(BedZwZhG4|64<=wvCn4)}w%Zx_TEs6ehmjVG&p5pi46r zg=3-3Q~;v55KR&8CfG;`Lv6NsXB}RqPVyNeKAfj9=Ol>fQlEUl2cH7=mPV!68+;jgtKvo5F#8&9m? z``w+#S5UR=QHFGM~noocC zVFa#v2%oo{%;wi~_~R2ci}`=B|0@ zinDfNxV3%iHIS(7{h_WEXqu!v~`CMH+7^SkvLe_3i}=pyDRah zN#L)F-`JLj6BiG}sj*WBmrdZuVVEo86Z<6VB}s)T$ZcWvG?i0cqI}WhUq2Y#{f~x# zi1LjxSZCwiKX}*ETGVzZ157=jydo*xC^}mJ<+)!DDCd4sx?VM%Y;&CTpw5;M*ihZ| zJ!FBJj0&j&-oJs?9a_I$;jzd%7|pdsQ3m`bPBe$nLoV1!YV8?Pw~0D zmSD-5Ue60>L$Rw;yk{_2d~v@CnvZa%!7{{7lb$kxWx!pzyh;6G~RbN5+|mFTbxcxf!XyfbLI^zMQSb6P~xzESXmV{9 zCMp)baZSz%)j&JWkc|Gq;_*$K@zQ%tH^91X2|Byv>=SmWR$7-shf|_^>Ll;*9+c(e z{N%43;&e8}_QGW+zE0m0myb-@QU%=Qo>``5UzB(lH0sK=E``{ZBl2Ni^-QtDp0ME1 zK88E-db_XBZQaU}cuvkCgH7crju~9eE-Y`os~0P-J=s;aS#wil$HGdK;Ut?dSO71ssyrdm{QRpMAV2nXslvlIE#+Oh>l7y_~?;}F!;ENCR zO+IG#NWIRI`FLntsz^FldCkky2f!d-%Pij9iLKr>IfCK);=}}?(NL%#4PfE(4kPQN zSC%BpZJ*P+PO5mHw0Wd%!zJsn&4g<$n#_?(=)JnoR2DK(mCPHp6e6VdV>?E5KCUF@ zf7W9wm%G#Wfm*NxTWIcJX-qtR=~NFxz4PSmDVAU8(B2wIm#IdHae-F{3jKQFiX?8NlKEhXR2Z|JCUd@HMnNVwqF~V9YJtD+T zQlOroDX-mg2% zBKV^Q5m5ECK{nWjJ7FHOSUi*a-C_?S_yo~G5HuRZH6R``^dS3Bh6u!nD`kFbxYThD zw~2%zL4tHA26rcdln4^=A(C+f9hLlcuMCv{8`u;?uoEVbU=YVNkBP#s3KnM@Oi)fQ zt_F3VjY)zASub%Q{Y?XgzlD3M5#gUBUuhW;$>uBSJH9UBfBtug*S|-;h?|L#^Z&uE zB&)spqM89dWg9ZrXi#F{KtL@r9g^xeR8J+$EhL~2u@cf`dS{8GUC76JP0hHtCKRg0 zt*rVyl&jaJAez;!fb!yX^+So4-8XMNpP@d3H*eF%t_?I|zN^1Iu5aGBXSm+}eCqn3 z^+vzcM*J>wV-FJRrx@^5;l>h0{OYT)lg{dr8!{s7(i{5T|3bivDoTonV1yo1@nVPR zXxEgGg^x5KHgp?=$xBwm_cKHeDurCgO>$B$GSO`Cd<~J8@>ni>Z-Ef!3+ck(MHVy@ z@#<*kCOb5S$V+Fvc@{Qv$oLfnOAG&YO5z_E2j6E z7a+c(>-`H)>g+6DeY1Y*ag-B6>Cl@@VhkZY@Uihe!{LlRpuTsmIsN4;+UDsHd954n9WZV6qq*{qZ5j<W)`UorOmXtVnLo3T{t#h3q^fooqQ~A+EY<$TDG4RKP*cK0liX95STt= zToC<2M2*(H1tZ)0s|v~iSAa^F-9jMwCy4cK0HM*3$@1Q`Pz}FFYm`PGP0wuamWrt*ehz3(|Fn%;0;K4}!Q~cx{0U0L=cs6lcrY^Y%Vf_rXpQIw~DfxB-72tZU6gdK8C~ea6(2P@kGH}!2N?>r(Ca{ zsI!6B!alPl%j1CHq97PTVRng$!~?s2{+6ffC#;X2z(Xb#9GsSYYe@9zY~7Dc7Hfgh z5Tq!})o30pA3ywg<9W3NpvUs;E%Cehz=s?EfLzcV0H?b{=q?vJCih2y%dhls6w3j$ zk9LB0L&(15mtul3T^QSK7KIZVTod#Sc)?1gzY~M=?ay87V}6G?F>~AIv()-N zD3rHX`;r;L{9N|Z8REN}OZB&SZ|5a80B%dQd-CNESP7HnuNn43T~Agcl1YOF@#W03 z1b*t!>t5G@XwVygHYczDIC|RdMB+ z$s5_5_W-EXN-u_5Pb{((!+8xa+?@_#dwtYHeJ_49Dql%3Fv0yXeV?!cC&Iqx@s~P%$X6%1 zYzS9pqaUv&aBQqO zBQs7d63FZIL1B&<8^oni%CZOdf6&;^oNqQ-9j-NBuQ^|9baQuZ^Jtyt&?cHq$Q9JE z5D>QY1?MU7%VVbvjysl~-a&ImiE(uFwHo{!kp;Jd`OLE!^4k8ID{`e-&>2uB7XB~= z+nIQGZ8-Sbfa}OrVPL}!mdieCrs3Nq8Ic_lpTKMIJ{h>XS$C3`h~ z?p2AbK~%t$t(NcOq5ZB3V|`a0io8A))v_PMt)Hg3x+07RL>i zGUq@t&+VV`kj55_snp?)Y@0rKZr`riC`9Q(B1P^nxffV9AvBLPrE<8D>ZP{HCDY@JIvYcYNRz8 z0Rf+Q0riSU@KaVpK)0M{2}Wuh!o~t*6>)EZSCQD{=}N4Oxjo1KO-MNpPYuPABh}E|rM!=TSl^F%NV^dg+>WNGi@Q5C z%JGsP#em`4LxDdIzA@VF&`2bLDv%J)(7vedDiXDqx{y6$Y0o~j*nVY73pINPCY?9y z$Rd&^64MN)Pkxr-CuZ+WqAJx6vuIAwmjkN{aPkrJ0I4F5-Bl}$hRzhRhZ^xN&Oe5$ za4Wrh6PyFfDG+Nzd8NTp2})j>pGtyejb&;NkU3C5-_H;{?>xK1QQ9S`xaHoMgee=2 zEbEh+*I!ggW@{T{qENlruZT)ODp~ZXHBc_Ngqu{jyC#qjyYGAQsO8VT^lts$z0HP+ z2xs^QjUwWuiEh863(PqO4BAosmhaK`pEI{-geBD9UuIn8ugOt-|6S(xkBLeGhW~)< z8aWBs0)bzOnY4wC$yW{M@&(iTe{8zhDnKP<1yr9J8akUK)1svAuxC)}x-<>S!9(?F zcA?{_C?@ZV2Aei`n#l(9zu`WS-hJsAXWt(SGp4(xg7~3*c5@odW;kXXbGuLOFMj{d z{gx81mQREmRAUHhfp#zoWh>z}GuS|raw1R#en%9R3hSR`qGglQhaq>#K!M%tooG;? zzjo}>sL7a3M5jW*s8R;#Y8b(l;%*I$@YH9)YzWR!T6WLI{$8ScBvw+5&()>NhPzd! z{>P(yk8{(G&2ovV^|#1HbcVMvXU&;0pk&6CxBTvBAB>#tK~qALsH`Ad1P0tAKWHv+BR8Fv4!`+>Obu1UX^Ov zmOpuS@Ui|NK4k-)TbG?+9T$)rkvq+?=0RDa=xdmY#JHLastjqPXdDbShqW>7NrHZ7 z7(9(HjM1-Ef(^`%3TlhySDJ27vQ?H`xr9VOM%0ANsA|A3-jj|r`KAo%oTajX3>^E` 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 YM{}PByk10KD_nuQ4E7Du?}+~TKh4V)`~Uy| literal 0 HcmV?d00001 diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..b7cb93e --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/mvnw b/mvnw new file mode 100755 index 0000000..8a8fb22 --- /dev/null +++ b/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..1d8ab01 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,188 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..855b8f9 --- /dev/null +++ b/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.6.3 + + + me.whiteship + effective-java-part1 + 0.0.1-SNAPSHOT + effective-java-part1 + effective-java-part1 + + 11 + + + + + com.google.guava + guava + 31.1-jre + + + com.google.auto.value + auto-value-annotations + 1.9 + + + com.google.auto.value + auto-value + 1.9 + + + + me.whiteship.hello + chinese-hello-service + 0.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter + + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-starter-test + test + + + + diff --git a/src/main/java/me/whiteship/chapter01/item01/ActionEnum.java b/src/main/java/me/whiteship/chapter01/item01/ActionEnum.java new file mode 100644 index 0000000..4a13404 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/ActionEnum.java @@ -0,0 +1,11 @@ +package me.whiteship.chapter01.item01; + +public enum ActionEnum { + ACTION_1(new App()) + , ACTION_2(new App()); + + private final App action; + + ActionEnum(App action) {this.action = action;} + +} \ No newline at end of file diff --git a/src/main/java/me/whiteship/chapter01/item01/AdvancedSettings.java b/src/main/java/me/whiteship/chapter01/item01/AdvancedSettings.java new file mode 100644 index 0000000..fbe7028 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/AdvancedSettings.java @@ -0,0 +1,8 @@ +package me.whiteship.chapter01.item01; + +public class AdvancedSettings { + + Settings settings; + + +} diff --git a/src/main/java/me/whiteship/chapter01/item01/App.java b/src/main/java/me/whiteship/chapter01/item01/App.java new file mode 100644 index 0000000..af910d4 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/App.java @@ -0,0 +1,13 @@ +package me.whiteship.chapter01.item01; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +public class App { + + public static void main(String[] args) { + ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); + HelloService helloService = applicationContext.getBean(HelloService.class); + System.out.println(helloService.hello()); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item01/AppConfig.java b/src/main/java/me/whiteship/chapter01/item01/AppConfig.java new file mode 100644 index 0000000..3634694 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/AppConfig.java @@ -0,0 +1,15 @@ +package me.whiteship.chapter01.item01; + +import me.whiteship.hello.ChineseHelloService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AppConfig { + + @Bean + public HelloService helloService() { + return new ChineseHelloService(); + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item01/Difficulty.java b/src/main/java/me/whiteship/chapter01/item01/Difficulty.java new file mode 100644 index 0000000..bb7c753 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/Difficulty.java @@ -0,0 +1,6 @@ +package me.whiteship.chapter01.item01; + +public enum Difficulty { + + EASY, NORMAL, HARD, HELL +} diff --git a/src/main/java/me/whiteship/chapter01/item01/HelloService.java b/src/main/java/me/whiteship/chapter01/item01/HelloService.java new file mode 100644 index 0000000..9d8b45b --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/HelloService.java @@ -0,0 +1,28 @@ +package me.whiteship.chapter01.item01; + +public interface HelloService { + + String hello(); + + static String hi() { + prepareMessage(); + return "hi"; + } + + static private void prepareMessage() { + } + + static String hi1() { + prepareMessage(); + return "hi"; + } + + static String hi2() { + prepareMessage(); + return "hi"; + } + + default String bye() { + return "bye"; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item01/HelloServiceFactory.java b/src/main/java/me/whiteship/chapter01/item01/HelloServiceFactory.java new file mode 100644 index 0000000..04cadc2 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/HelloServiceFactory.java @@ -0,0 +1,28 @@ +package me.whiteship.chapter01.item01; + +import me.whiteship.hello.ChineseHelloService; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Optional; +import java.util.ServiceLoader; + +public class HelloServiceFactory { + + public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + ServiceLoader loader = ServiceLoader.load(HelloService.class); + Optional helloServiceOptional = loader.findFirst(); + helloServiceOptional.ifPresent(h -> { + System.out.println(h.hello()); + }); + + HelloService helloService = new ChineseHelloService(); + System.out.println(helloService.hello()); + +// Class aClass = Class.forName("me.whiteship.hello.ChineseHelloService"); +// Constructor constructor = aClass.getConstructor(); +// HelloService helloService = (HelloService) constructor.newInstance(); +// System.out.println(helloService.hello()); + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item01/ListQuiz.java b/src/main/java/me/whiteship/chapter01/item01/ListQuiz.java new file mode 100644 index 0000000..5c3a549 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/ListQuiz.java @@ -0,0 +1,24 @@ +package me.whiteship.chapter01.item01; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class ListQuiz { + + public static void main(String[] args) { + List numbers = new ArrayList(); + numbers.add(100); + numbers.add(20); + numbers.add(44); + numbers.add(3); + + System.out.println(numbers); + + Comparator desc = (o1, o2) -> o2 - o1; + + numbers.sort(desc.reversed()); + + System.out.println(numbers); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item01/Order.java b/src/main/java/me/whiteship/chapter01/item01/Order.java new file mode 100644 index 0000000..6c959ea --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/Order.java @@ -0,0 +1,38 @@ +package me.whiteship.chapter01.item01; + +import java.util.*; + +public class Order { + + private boolean prime; + + private boolean urgent; + + private Product product; + + private OrderStatus orderStatus; + + public static Order primeOrder(Product product) { + Order order = new Order(); + order.prime = true; + order.product = product; + + return order; + } + + public static Order urgentOrder(Product product) { + Order order = new Order(); + order.urgent = true; + order.product = product; + return order; + } + + public static void main(String[] args) { + + Order order = new Order(); + if (order.orderStatus == OrderStatus.DELIVERED) { + System.out.println("delivered"); + } + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item01/OrderStatus.java b/src/main/java/me/whiteship/chapter01/item01/OrderStatus.java new file mode 100644 index 0000000..785b204 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/OrderStatus.java @@ -0,0 +1,12 @@ +package me.whiteship.chapter01.item01; + +public enum OrderStatus { + + PREPARING(0), SHIPPED(1), DELIVERING(2), DELIVERED(3); + + private int number; + + OrderStatus(int number) { + this.number = number; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item01/Product.java b/src/main/java/me/whiteship/chapter01/item01/Product.java new file mode 100644 index 0000000..7891629 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/Product.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter01.item01; + +import java.util.EnumSet; +import java.util.Set; + +public class Product { + + public static void main(String[] args) { + Settings settings1 = Settings.getInstance(); + Settings settings2 = Settings.getInstance(); + + System.out.println(settings1); + System.out.println(settings2); + + Boolean.valueOf(false); + EnumSet.allOf(Difficulty.class); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item01/Settings.java b/src/main/java/me/whiteship/chapter01/item01/Settings.java new file mode 100644 index 0000000..a5566ba --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item01/Settings.java @@ -0,0 +1,23 @@ +package me.whiteship.chapter01.item01; + +/** + * 이 클래스의 인스턴스는 #getInstance()를 통해 사용한다. + * @see #getInstance() + */ +public class Settings { + + private boolean useAutoSteering; + + private boolean useABS; + + private Difficulty difficulty; + + private Settings() {} + + private static final Settings SETTINGS = new Settings(); + + public static Settings getInstance() { + return SETTINGS; + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item02/builder/BuilderTest.java b/src/main/java/me/whiteship/chapter01/item02/builder/BuilderTest.java new file mode 100644 index 0000000..f505b26 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/builder/BuilderTest.java @@ -0,0 +1,10 @@ +package me.whiteship.chapter01.item02.builder; + +public class BuilderTest { + + public static void main(String[] args) { + new NutritionFacts.Builder(10, 10) + .calories(10) + .build(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item02/builder/NutritionFacts.java b/src/main/java/me/whiteship/chapter01/item02/builder/NutritionFacts.java new file mode 100644 index 0000000..78d00c4 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/builder/NutritionFacts.java @@ -0,0 +1,57 @@ +package me.whiteship.chapter01.item02.builder; + +// 코드 2-3 빌더 패턴 - 점층적 생성자 패턴과 자바빈즈 패턴의 장점만 취했다. (17~18쪽) +public class NutritionFacts { + private final int servingSize; + private final int servings; + private final int calories; + private final int fat; + private final int sodium; + private final int carbohydrate; + + public static void main(String[] args) { + NutritionFacts cocaCola = new Builder(240, 8) + .calories(100) + .sodium(35) + .carbohydrate(27).build(); + } + + public static class Builder { + // 필수 매개변수 + private final int servingSize; + private final int servings; + + // 선택 매개변수 - 기본값으로 초기화한다. + private int calories = 0; + private int fat = 0; + private int sodium = 0; + private int carbohydrate = 0; + + public Builder(int servingSize, int servings) { + this.servingSize = servingSize; + this.servings = servings; + } + + public Builder calories(int val) + { calories = val; return this; } + public Builder fat(int val) + { fat = val; return this; } + public Builder sodium(int val) + { sodium = val; return this; } + public Builder carbohydrate(int val) + { carbohydrate = val; return this; } + + public NutritionFacts build() { + return new NutritionFacts(this); + } + } + + private NutritionFacts(Builder builder) { + servingSize = builder.servingSize; + servings = builder.servings; + calories = builder.calories; + fat = builder.fat; + sodium = builder.sodium; + carbohydrate = builder.carbohydrate; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item02/freeze/FreezeTest.js b/src/main/java/me/whiteship/chapter01/item02/freeze/FreezeTest.js new file mode 100644 index 0000000..8991197 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/freeze/FreezeTest.js @@ -0,0 +1,10 @@ +const keesun = { + 'name': 'Keesun', + 'age': 40 +}; + +Object.freeze(keesun); + +keesun.kids = ["서연"]; + +console.info(keesun.name); \ No newline at end of file diff --git a/src/main/java/me/whiteship/chapter01/item02/freeze/Person.java b/src/main/java/me/whiteship/chapter01/item02/freeze/Person.java new file mode 100644 index 0000000..3d1781e --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/freeze/Person.java @@ -0,0 +1,24 @@ +package me.whiteship.chapter01.item02.freeze; + +import java.util.ArrayList; +import java.util.List; + +public class Person { + + private final String name; + + private final int birthYear; + + private final List kids; + + public Person(String name, int birthYear) { + this.name = name; + this.birthYear = birthYear; + this.kids = new ArrayList<>(); + } + + public static void main(String[] args) { + Person person = new Person("keesun", 1982); + + } +} diff --git a/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/Calzone.java b/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/Calzone.java new file mode 100644 index 0000000..5ef1df5 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/Calzone.java @@ -0,0 +1,31 @@ +package me.whiteship.chapter01.item02.hierarchicalbuilder; + +// 코드 2-6 칼초네 피자 - 계층적 빌더를 활용한 하위 클래스 (20~21쪽) +public class Calzone extends Pizza { + private final boolean sauceInside; + + public static class Builder extends Pizza.Builder { + private boolean sauceInside = false; // 기본값 + + public Builder sauceInside() { + sauceInside = true; + return this; + } + + @Override public Calzone build() { + return new Calzone(this); + } + + @Override protected Builder self() { return this; } + } + + private Calzone(Builder builder) { + super(builder); + sauceInside = builder.sauceInside; + } + + @Override public String toString() { + return String.format("%s로 토핑한 칼초네 피자 (소스는 %s에)", + toppings, sauceInside ? "안" : "바깥"); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/NyPizza.java b/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/NyPizza.java new file mode 100644 index 0000000..b0f04c1 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/NyPizza.java @@ -0,0 +1,32 @@ +package me.whiteship.chapter01.item02.hierarchicalbuilder; + +import java.util.Objects; + +// 코드 2-5 뉴욕 피자 - 계층적 빌더를 활용한 하위 클래스 (20쪽) +public class NyPizza extends Pizza { + public enum Size { SMALL, MEDIUM, LARGE } + private final Size size; + + public static class Builder extends Pizza.Builder { + private final Size size; + + public Builder(Size size) { + this.size = Objects.requireNonNull(size); + } + + @Override public NyPizza build() { + return new NyPizza(this); + } + + @Override protected Builder self() { return this; } + } + + private NyPizza(Builder builder) { + super(builder); + size = builder.size; + } + + @Override public String toString() { + return toppings + "로 토핑한 뉴욕 피자"; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/Pizza.java b/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/Pizza.java new file mode 100644 index 0000000..edb3dd0 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/Pizza.java @@ -0,0 +1,33 @@ +package me.whiteship.chapter01.item02.hierarchicalbuilder; + +import java.util.EnumSet; +import java.util.Objects; +import java.util.Set; + +// 코드 2-4 계층적으로 설계된 클래스와 잘 어울리는 빌더 패턴 (19쪽) + +// 참고: 여기서 사용한 '시뮬레이트한 셀프 타입(simulated self-type)' 관용구는 +// 빌더뿐 아니라 임의의 유동적인 계층구조를 허용한다. + +public abstract class Pizza { + public enum Topping { HAM, MUSHROOM, ONION, PEPPER, SAUSAGE } + final Set toppings; + + abstract static class Builder> { + EnumSet toppings = EnumSet.noneOf(Topping.class); + public T addTopping(Topping topping) { + toppings.add(Objects.requireNonNull(topping)); + return self(); + } + + abstract Pizza build(); + + // 하위 클래스는 이 메서드를 재정의(overriding)하여 + // "this"를 반환하도록 해야 한다. + protected abstract T self(); + } + + Pizza(Builder builder) { + toppings = builder.toppings.clone(); // 아이템 50 참조 + } +} diff --git a/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/PizzaTest.java b/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/PizzaTest.java new file mode 100644 index 0000000..797365e --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/hierarchicalbuilder/PizzaTest.java @@ -0,0 +1,20 @@ +package me.whiteship.chapter01.item02.hierarchicalbuilder; + + +import static me.whiteship.chapter01.item02.hierarchicalbuilder.NyPizza.Size.SMALL; +import static me.whiteship.chapter01.item02.hierarchicalbuilder.Pizza.Topping.*; + +// 계층적 빌더 사용 (21쪽) +public class PizzaTest { + public static void main(String[] args) { + NyPizza pizza = new NyPizza.Builder(SMALL) + .addTopping(SAUSAGE) + .addTopping(ONION).build(); + + Calzone calzone = new Calzone.Builder() + .addTopping(HAM).sauceInside().build(); + + System.out.println(pizza); + System.out.println(calzone); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item02/illegalargumentexception/Order.java b/src/main/java/me/whiteship/chapter01/item02/illegalargumentexception/Order.java new file mode 100644 index 0000000..35ac437 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/illegalargumentexception/Order.java @@ -0,0 +1,20 @@ +package me.whiteship.chapter01.item02.illegalargumentexception; + +import java.time.LocalDate; + +public class Order { + + public void updateDeliveryDate(LocalDate deliveryDate) { + if (deliveryDate == null) { + throw new NullPointerException("deliveryDate can't be null"); + } + + if (deliveryDate.isBefore(LocalDate.now())) { + //TODO 과거로 배송 해달라고?? + throw new IllegalArgumentException("deliveryDate can't be earlier than " + LocalDate.now()); + } + + // 배송 날짜 업데이트 + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item02/javabeans/NutritionFacts.java b/src/main/java/me/whiteship/chapter01/item02/javabeans/NutritionFacts.java new file mode 100644 index 0000000..9e829e8 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/javabeans/NutritionFacts.java @@ -0,0 +1,53 @@ +package me.whiteship.chapter01.item02.javabeans; + +// 코드 2-2 자바빈즈 패턴 - 일관성이 깨지고, 불변으로 만들 수 없다. (16쪽) +public class NutritionFacts { + // 필드 (기본값이 있다면) 기본값으로 초기화된다. + private int servingSize = -1; // 필수; 기본값 없음 + private int servings = -1; // 필수; 기본값 없음 + private int calories = 0; + private int fat = 0; + private int sodium = 0; + private int carbohydrate = 0; + private boolean healthy; + + public NutritionFacts() { } + + public void setServingSize(int servingSize) { + this.servingSize = servingSize; + } + + public void setServings(int servings) { + this.servings = servings; + } + + public void setCalories(int calories) { + this.calories = calories; + } + + public void setFat(int fat) { + this.fat = fat; + } + + public void setSodium(int sodium) { + this.sodium = sodium; + } + + public void setCarbohydrate(int carbohydrate) { + this.carbohydrate = carbohydrate; + } + + public void setHealthy(boolean healthy) { + this.healthy = healthy; + } + + public static void main(String[] args) { + NutritionFacts cocaCola = new NutritionFacts(); + cocaCola.setServingSize(240); + cocaCola.setServings(8); + + cocaCola.setCalories(100); + cocaCola.setSodium(35); + cocaCola.setCarbohydrate(27); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item02/telescopingconstructor/NutritionFacts.java b/src/main/java/me/whiteship/chapter01/item02/telescopingconstructor/NutritionFacts.java new file mode 100644 index 0000000..e9bc38f --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/telescopingconstructor/NutritionFacts.java @@ -0,0 +1,46 @@ +package me.whiteship.chapter01.item02.telescopingconstructor; + +// 코드 2-1 점층적 생성자 패턴 - 확장하기 어렵다! (14~15쪽) +public class NutritionFacts { + private final int servingSize; // (mL, 1회 제공량) 필수 + private final int servings; // (회, 총 n회 제공량) 필수 + private final int calories; // (1회 제공량당) 선택 + private final int fat; // (g/1회 제공량) 선택 + private final int sodium; // (mg/1회 제공량) 선택 + private final int carbohydrate; // (g/1회 제공량) 선택 + + public NutritionFacts(int servingSize, int servings) { + this(servingSize, servings, 0); + } + + public NutritionFacts(int servingSize, int servings, + int calories) { + this(servingSize, servings, calories, 0); + } + + public NutritionFacts(int servingSize, int servings, + int calories, int fat) { + this(servingSize, servings, calories, fat, 0); + } + + public NutritionFacts(int servingSize, int servings, + int calories, int fat, int sodium) { + this(servingSize, servings, calories, fat, sodium, 0); + } + + public NutritionFacts(int servingSize, int servings, + int calories, int fat, int sodium, int carbohydrate) { + this.servingSize = servingSize; + this.servings = servings; + this.calories = calories; + this.fat = fat; + this.sodium = sodium; + this.carbohydrate = carbohydrate; + } + + public static void main(String[] args) { + NutritionFacts cocaCola = + new NutritionFacts(10, 10); + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item02/varargs/VarargsSamples.java b/src/main/java/me/whiteship/chapter01/item02/varargs/VarargsSamples.java new file mode 100644 index 0000000..692780f --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item02/varargs/VarargsSamples.java @@ -0,0 +1,17 @@ +package me.whiteship.chapter01.item02.varargs; + +import java.util.Arrays; + +public class VarargsSamples { + + public void printNumbers(int... numbers) { + System.out.println(numbers.getClass().getCanonicalName()); + System.out.println(numbers.getClass().getComponentType()); + Arrays.stream(numbers).forEach(System.out::println); + } + + public static void main(String[] args) { + VarargsSamples samples = new VarargsSamples(); + samples.printNumbers(1, 20, 20, 39, 59); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/enumtype/Elvis.java b/src/main/java/me/whiteship/chapter01/item03/enumtype/Elvis.java new file mode 100644 index 0000000..2162896 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/enumtype/Elvis.java @@ -0,0 +1,16 @@ +package me.whiteship.chapter01.item03.enumtype; + +// 열거 타입 방식의 싱글턴 - 바람직한 방법 (25쪽) +public enum Elvis { + INSTANCE; + + public void leaveTheBuilding() { + System.out.println("기다려 자기야, 지금 나갈께!"); + } + + // 이 메서드는 보통 클래스 바깥(다른 클래스)에 작성해야 한다! + public static void main(String[] args) { + Elvis elvis = Elvis.INSTANCE; + elvis.leaveTheBuilding(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/enumtype/EnumElvisReflection.java b/src/main/java/me/whiteship/chapter01/item03/enumtype/EnumElvisReflection.java new file mode 100644 index 0000000..67cffdf --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/enumtype/EnumElvisReflection.java @@ -0,0 +1,15 @@ +package me.whiteship.chapter01.item03.enumtype; + +import java.lang.reflect.Constructor; + +public class EnumElvisReflection { + + public static void main(String[] args) { + try { + Constructor declaredConstructor = Elvis.class.getDeclaredConstructor(); + System.out.println(declaredConstructor); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/enumtype/EnumElvisSerialization.java b/src/main/java/me/whiteship/chapter01/item03/enumtype/EnumElvisSerialization.java new file mode 100644 index 0000000..b67a348 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/enumtype/EnumElvisSerialization.java @@ -0,0 +1,23 @@ +package me.whiteship.chapter01.item03.enumtype; + +import me.whiteship.chapter01.item03.field.Elvis; + +import java.io.*; + +public class EnumElvisSerialization { + + public static void main(String[] args) { + try (ObjectOutput out = new ObjectOutputStream(new FileOutputStream("elvis.obj"))) { + out.writeObject(Elvis.INSTANCE); + } catch (IOException e) { + e.printStackTrace(); + } + + try (ObjectInput in = new ObjectInputStream(new FileInputStream("elvis.obj"))) { + Elvis elvis = (Elvis) in.readObject(); + System.out.println(elvis == Elvis.INSTANCE); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/field/Concert.java b/src/main/java/me/whiteship/chapter01/item03/field/Concert.java new file mode 100644 index 0000000..a357c35 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/field/Concert.java @@ -0,0 +1,28 @@ +package me.whiteship.chapter01.item03.field; + +public class Concert { + + private boolean lightsOn; + + private boolean mainStateOpen; + + private IElvis elvis; + + public Concert(IElvis elvis) { + this.elvis = elvis; + } + + public void perform() { + mainStateOpen = true; + lightsOn = true; + elvis.sing(); + } + + public boolean isLightsOn() { + return lightsOn; + } + + public boolean isMainStateOpen() { + return mainStateOpen; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/field/Elvis.java b/src/main/java/me/whiteship/chapter01/item03/field/Elvis.java new file mode 100644 index 0000000..f72600a --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/field/Elvis.java @@ -0,0 +1,40 @@ +package me.whiteship.chapter01.item03.field; + +import java.io.Serializable; + +// 코드 3-1 public static final 필드 방식의 싱글턴 (23쪽) +public class Elvis implements IElvis, Serializable { + + /** + * 싱글톤 오브젝트 + */ + public static final Elvis INSTANCE = new Elvis(); + private static boolean created; + + private Elvis() { + if (created) { + throw new UnsupportedOperationException("can't be created by constructor."); + } + + created = true; + } + + public void leaveTheBuilding() { + System.out.println("Whoa baby, I'm outta here!"); + } + + public void sing() { + System.out.println("I'll have a blue~ Christmas without you~"); + } + + // 이 메서드는 보통 클래스 바깥(다른 클래스)에 작성해야 한다! + public static void main(String[] args) { + Elvis elvis = Elvis.INSTANCE; + elvis.leaveTheBuilding(); + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item03/field/ElvisReflection.java b/src/main/java/me/whiteship/chapter01/item03/field/ElvisReflection.java new file mode 100644 index 0000000..e9c0211 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/field/ElvisReflection.java @@ -0,0 +1,21 @@ +package me.whiteship.chapter01.item03.field; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +// 생성자로 여러 인스턴스 만들기 +public class ElvisReflection { + + public static void main(String[] args) { + try { + Constructor defaultConstructor = Elvis.class.getDeclaredConstructor(); + defaultConstructor.setAccessible(true); + Elvis elvis1 = defaultConstructor.newInstance(); + Elvis elvis2 = defaultConstructor.newInstance(); + Elvis.INSTANCE.sing(); + } catch (InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item03/field/ElvisSerialization.java b/src/main/java/me/whiteship/chapter01/item03/field/ElvisSerialization.java new file mode 100644 index 0000000..6507ed7 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/field/ElvisSerialization.java @@ -0,0 +1,23 @@ +package me.whiteship.chapter01.item03.field; + +import java.io.*; + +// 역직렬화로 여러 인스턴스 만들기 +public class ElvisSerialization { + + public static void main(String[] args) { + try (ObjectOutput out = new ObjectOutputStream(new FileOutputStream("elvis.obj"))) { + out.writeObject(Elvis.INSTANCE); + } catch (IOException e) { + e.printStackTrace(); + } + + try (ObjectInput in = new ObjectInputStream(new FileInputStream("elvis.obj"))) { + Elvis elvis3 = (Elvis) in.readObject(); + System.out.println(elvis3 == Elvis.INSTANCE); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item03/field/IElvis.java b/src/main/java/me/whiteship/chapter01/item03/field/IElvis.java new file mode 100644 index 0000000..fd60bfa --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/field/IElvis.java @@ -0,0 +1,8 @@ +package me.whiteship.chapter01.item03.field; + +public interface IElvis { + + void leaveTheBuilding(); + + void sing(); +} diff --git a/src/main/java/me/whiteship/chapter01/item03/functionalinterface/DefaultFunctions.java b/src/main/java/me/whiteship/chapter01/item03/functionalinterface/DefaultFunctions.java new file mode 100644 index 0000000..672c493 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/functionalinterface/DefaultFunctions.java @@ -0,0 +1,24 @@ +package me.whiteship.chapter01.item03.functionalinterface; + + +import me.whiteship.chapter01.item03.methodreference.Person; + +import java.time.LocalDate; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public class DefaultFunctions { + + public static void main(String[] args) { + Function intToString = Object::toString; + + Supplier personSupplier = Person::new; + Function personFunction = Person::new; + + Consumer integerConsumer = System.out::println; + + Predicate predicate; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/functionalinterface/MyFunction.java b/src/main/java/me/whiteship/chapter01/item03/functionalinterface/MyFunction.java new file mode 100644 index 0000000..521a650 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/functionalinterface/MyFunction.java @@ -0,0 +1,11 @@ +package me.whiteship.chapter01.item03.functionalinterface; + +@FunctionalInterface +public interface MyFunction { + + String valueOf(Integer integer); + + static String hello() { + return "hello"; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/functionalinterface/UsageOfFunctions.java b/src/main/java/me/whiteship/chapter01/item03/functionalinterface/UsageOfFunctions.java new file mode 100644 index 0000000..ec8071c --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/functionalinterface/UsageOfFunctions.java @@ -0,0 +1,21 @@ +package me.whiteship.chapter01.item03.functionalinterface; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class UsageOfFunctions { + + public static void main(String[] args) { + List dates = new ArrayList<>(); + dates.add(LocalDate.of(1982, 7, 15)); + dates.add(LocalDate.of(2011, 3, 2)); + dates.add(LocalDate.of(2013, 1, 28)); + + List before2000 = dates.stream() + .filter(d -> d.isBefore(LocalDate.of(2000, 1, 1))) + .map(LocalDate::getYear) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/methodreference/Person.java b/src/main/java/me/whiteship/chapter01/item03/methodreference/Person.java new file mode 100644 index 0000000..835ca38 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/methodreference/Person.java @@ -0,0 +1,42 @@ +package me.whiteship.chapter01.item03.methodreference; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class Person { + + LocalDate birthday; + + public Person() { + + } + + public Person(LocalDate birthday) { + this.birthday = birthday; + } + + public static int compareByAge(Person a, Person b) { + return a.birthday.compareTo(b.birthday); + } + + public static void main(String[] args) { + List people = new ArrayList<>(); + people.add(new Person(LocalDate.of(1982, 7, 15))); + people.add(new Person(LocalDate.of(2011, 3, 2))); + people.add(new Person(LocalDate.of(2013, 1, 28))); + + people.sort(new Comparator() { + @Override + public int compare(Person a, Person b) { + return a.birthday.compareTo(b.birthday); + } + }); + } + + public int getAge() { + return LocalDate.now().getYear() - birthday.getYear(); + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item03/serialization/Book.java b/src/main/java/me/whiteship/chapter01/item03/serialization/Book.java new file mode 100644 index 0000000..940329d --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/serialization/Book.java @@ -0,0 +1,67 @@ +package me.whiteship.chapter01.item03.serialization; + +import java.io.Serializable; +import java.time.LocalDate; + +public class Book implements Serializable { + + private static final long serialVersionUID = 1L; + + private String isbn; + + private String title; + + private LocalDate published; + + private String name; + + private transient int numberOfSold; + + public Book(String isbn, String title, String author, LocalDate published) { + this.isbn = isbn; + this.title = title; + this.published = published; + } + + @Override + public String toString() { + return "Book{" + + "isbn='" + isbn + '\'' + + ", title='" + title + '\'' + + ", published=" + published + + ", numberOfSold=" + numberOfSold + + '}'; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public LocalDate getPublished() { + return published; + } + + public void setPublished(LocalDate published) { + this.published = published; + } + + public int getNumberOfSold() { + return numberOfSold; + } + + public void setNumberOfSold(int numberOfSold) { + this.numberOfSold = numberOfSold; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/serialization/SerializationExample.java b/src/main/java/me/whiteship/chapter01/item03/serialization/SerializationExample.java new file mode 100644 index 0000000..0fa0074 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/serialization/SerializationExample.java @@ -0,0 +1,36 @@ +package me.whiteship.chapter01.item03.serialization; + +import java.io.*; +import java.time.LocalDate; + +public class SerializationExample { + + private void serialize(Book book) { + try (ObjectOutput out = new ObjectOutputStream(new FileOutputStream("book.obj"))) { + out.writeObject(book); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Book deserialize() { + try (ObjectInput in = new ObjectInputStream(new FileInputStream("book.obj"))) { + return (Book) in.readObject(); + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { +// Book book = new Book("12345", "이팩티브 자바 완벽 공략", "백기선", +// LocalDate.of(2022, 3, 21)); +// book.setNumberOfSold(200); + + SerializationExample example = new SerializationExample(); +// example.serialize(book); + Book deserializedBook = example.deserialize(); + +// System.out.println(book); + System.out.println(deserializedBook); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/staticfactory/Concert.java b/src/main/java/me/whiteship/chapter01/item03/staticfactory/Concert.java new file mode 100644 index 0000000..8abaf76 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/staticfactory/Concert.java @@ -0,0 +1,16 @@ +package me.whiteship.chapter01.item03.staticfactory; + +import java.util.function.Supplier; + +public class Concert { + + public void start(Supplier singerSupplier) { + Singer singer = singerSupplier.get(); + singer.sing(); + } + + public static void main(String[] args) { + Concert concert = new Concert(); + concert.start(Elvis::getInstance); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/staticfactory/Elvis.java b/src/main/java/me/whiteship/chapter01/item03/staticfactory/Elvis.java new file mode 100644 index 0000000..382c222 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/staticfactory/Elvis.java @@ -0,0 +1,26 @@ +package me.whiteship.chapter01.item03.staticfactory; + +// 코드 3-2 정적 팩터리 방식의 싱글턴 (24쪽) +public class Elvis implements Singer { + private static final Elvis INSTANCE = new Elvis(); + private Elvis() { } + public static Elvis getInstance() { return INSTANCE; } + + public void leaveTheBuilding() { + System.out.println("Whoa baby, I'm outta here!"); + } + + // 이 메서드는 보통 클래스 바깥(다른 클래스)에 작성해야 한다! + public static void main(String[] args) { + Elvis elvis = Elvis.getInstance(); + elvis.leaveTheBuilding(); + + System.out.println(Elvis.getInstance()); + System.out.println(Elvis.getInstance()); + } + + @Override + public void sing() { + System.out.println("my way~~~"); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item03/staticfactory/MetaElvis.java b/src/main/java/me/whiteship/chapter01/item03/staticfactory/MetaElvis.java new file mode 100644 index 0000000..ce30e64 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/staticfactory/MetaElvis.java @@ -0,0 +1,32 @@ +package me.whiteship.chapter01.item03.staticfactory; + +import java.util.Objects; + +// 코드 3-2 제네릭 싱글톤 팩토리 (24쪽) +public class MetaElvis { + + private static final MetaElvis INSTANCE = new MetaElvis<>(); + + private MetaElvis() { } + + @SuppressWarnings("unchecked") + public static MetaElvis getInstance() { return (MetaElvis) INSTANCE; } + + public void say(T t) { + System.out.println(t); + } + + public void leaveTheBuilding() { + System.out.println("Whoa baby, I'm outta here!"); + } + + public static void main(String[] args) { + MetaElvis elvis1 = MetaElvis.getInstance(); + MetaElvis elvis2 = MetaElvis.getInstance(); + System.out.println(elvis1); + System.out.println(elvis2); + elvis1.say("hello"); + elvis2.say(100); + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item03/staticfactory/Singer.java b/src/main/java/me/whiteship/chapter01/item03/staticfactory/Singer.java new file mode 100644 index 0000000..1d607f0 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item03/staticfactory/Singer.java @@ -0,0 +1,6 @@ +package me.whiteship.chapter01.item03.staticfactory; + +public interface Singer { + + void sing(); +} diff --git a/src/main/java/me/whiteship/chapter01/item04/DefaultUtilityClass.java b/src/main/java/me/whiteship/chapter01/item04/DefaultUtilityClass.java new file mode 100644 index 0000000..1d3b932 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item04/DefaultUtilityClass.java @@ -0,0 +1,9 @@ +package me.whiteship.chapter01.item04; + +public class DefaultUtilityClass extends UtilityClass { + + public static void main(String[] args) { + DefaultUtilityClass utilityClass = new DefaultUtilityClass(); + utilityClass.hello(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item04/UtilityClass.java b/src/main/java/me/whiteship/chapter01/item04/UtilityClass.java new file mode 100644 index 0000000..5afb751 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item04/UtilityClass.java @@ -0,0 +1,26 @@ +package me.whiteship.chapter01.item04; + +import org.springframework.context.annotation.AnnotationConfigUtils; + +public class UtilityClass { + + /** + * 이 클래스는 인스턴스를 만들 수 없습니다. + */ +// private UtilityClass() { +// throw new AssertionError(); +// } + + public static String hello() { + return "hello"; + } + + public static void main(String[] args) { + String hello = UtilityClass.hello(); + + UtilityClass utilityClass = new UtilityClass(); + utilityClass.hello(); + + + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/DefaultDictionary.java b/src/main/java/me/whiteship/chapter01/item05/DefaultDictionary.java new file mode 100644 index 0000000..e02a16d --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/DefaultDictionary.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter01.item05; + +import org.springframework.stereotype.Component; + +import java.util.List; + +public class DefaultDictionary implements Dictionary{ + + @Override + public boolean contains(String word) { + return false; + } + + @Override + public List closeWordsTo(String typo) { + return null; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/Dictionary.java b/src/main/java/me/whiteship/chapter01/item05/Dictionary.java new file mode 100644 index 0000000..1f6ac9b --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/Dictionary.java @@ -0,0 +1,10 @@ +package me.whiteship.chapter01.item05; + +import java.util.List; + +public interface Dictionary { + + boolean contains(String word); + + List closeWordsTo(String typo); +} diff --git a/src/main/java/me/whiteship/chapter01/item05/MockDictionary.java b/src/main/java/me/whiteship/chapter01/item05/MockDictionary.java new file mode 100644 index 0000000..adc401a --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/MockDictionary.java @@ -0,0 +1,15 @@ +package me.whiteship.chapter01.item05; + +import java.util.List; + +public class MockDictionary implements Dictionary{ + @Override + public boolean contains(String word) { + return false; + } + + @Override + public List closeWordsTo(String typo) { + return null; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/dependencyinjection/DictionaryFactory.java b/src/main/java/me/whiteship/chapter01/item05/dependencyinjection/DictionaryFactory.java new file mode 100644 index 0000000..ee41ce9 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/dependencyinjection/DictionaryFactory.java @@ -0,0 +1,9 @@ +package me.whiteship.chapter01.item05.dependencyinjection; + +import me.whiteship.chapter01.item05.DefaultDictionary; + +public class DictionaryFactory { + public static DefaultDictionary get() { + return new DefaultDictionary(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/dependencyinjection/SpellChecker.java b/src/main/java/me/whiteship/chapter01/item05/dependencyinjection/SpellChecker.java new file mode 100644 index 0000000..787b437 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/dependencyinjection/SpellChecker.java @@ -0,0 +1,29 @@ +package me.whiteship.chapter01.item05.dependencyinjection; + +import me.whiteship.chapter01.item05.Dictionary; + +import java.util.List; +import java.util.function.Supplier; + +public class SpellChecker { + + private final Dictionary dictionary; + + public SpellChecker(Dictionary dictionary) { + this.dictionary = dictionary; + } + + public SpellChecker(Supplier dictionarySupplier) { + this.dictionary = dictionarySupplier.get(); + } + + public boolean isValid(String word) { + // TODO 여기 SpellChecker 코드 + return dictionary.contains(word); + } + + public List suggestions(String typo) { + // TODO 여기 SpellChecker 코드 + return dictionary.closeWordsTo(typo); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/factorymethod/DefaultDictionaryFactory.java b/src/main/java/me/whiteship/chapter01/item05/factorymethod/DefaultDictionaryFactory.java new file mode 100644 index 0000000..ee40273 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/factorymethod/DefaultDictionaryFactory.java @@ -0,0 +1,11 @@ +package me.whiteship.chapter01.item05.factorymethod; + +import me.whiteship.chapter01.item05.DefaultDictionary; +import me.whiteship.chapter01.item05.Dictionary; + +public class DefaultDictionaryFactory implements DictionaryFactory { + @Override + public Dictionary getDictionary() { + return new DefaultDictionary(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/factorymethod/DictionaryFactory.java b/src/main/java/me/whiteship/chapter01/item05/factorymethod/DictionaryFactory.java new file mode 100644 index 0000000..7964e30 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/factorymethod/DictionaryFactory.java @@ -0,0 +1,9 @@ +package me.whiteship.chapter01.item05.factorymethod; + +import me.whiteship.chapter01.item05.Dictionary; + +public interface DictionaryFactory { + + Dictionary getDictionary(); + +} diff --git a/src/main/java/me/whiteship/chapter01/item05/factorymethod/MockDictionaryFactory.java b/src/main/java/me/whiteship/chapter01/item05/factorymethod/MockDictionaryFactory.java new file mode 100644 index 0000000..d644636 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/factorymethod/MockDictionaryFactory.java @@ -0,0 +1,12 @@ +package me.whiteship.chapter01.item05.factorymethod; + +import me.whiteship.chapter01.item05.DefaultDictionary; +import me.whiteship.chapter01.item05.Dictionary; +import me.whiteship.chapter01.item05.MockDictionary; + +public class MockDictionaryFactory implements DictionaryFactory { + @Override + public Dictionary getDictionary() { + return new MockDictionary(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/factorymethod/SpellChecker.java b/src/main/java/me/whiteship/chapter01/item05/factorymethod/SpellChecker.java new file mode 100644 index 0000000..eae6e99 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/factorymethod/SpellChecker.java @@ -0,0 +1,25 @@ +package me.whiteship.chapter01.item05.factorymethod; + +import me.whiteship.chapter01.item05.Dictionary; + +import java.util.List; + +public class SpellChecker { + + private Dictionary dictionary; + + public SpellChecker(DictionaryFactory dictionaryFactory) { + this.dictionary = dictionaryFactory.getDictionary(); + } + + public boolean isValid(String word) { + // TODO 여기 SpellChecker 코드 + return dictionary.contains(word); + } + + public List suggestions(String typo) { + // TODO 여기 SpellChecker 코드 + return dictionary.closeWordsTo(typo); + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item05/package-info.java b/src/main/java/me/whiteship/chapter01/item05/package-info.java new file mode 100644 index 0000000..e55642a --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/package-info.java @@ -0,0 +1 @@ +package me.whiteship.chapter01.item05; \ No newline at end of file diff --git a/src/main/java/me/whiteship/chapter01/item05/singleton/SpellChecker.java b/src/main/java/me/whiteship/chapter01/item05/singleton/SpellChecker.java new file mode 100644 index 0000000..d0dc41e --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/singleton/SpellChecker.java @@ -0,0 +1,25 @@ +package me.whiteship.chapter01.item05.singleton; + +import me.whiteship.chapter01.item05.DefaultDictionary; +import me.whiteship.chapter01.item05.Dictionary; + +import java.util.List; + +public class SpellChecker { + + private final Dictionary dictionary = new DefaultDictionary(); + + private SpellChecker() {} + + public static final SpellChecker INSTANCE = new SpellChecker(); + + public boolean isValid(String word) { + // TODO 여기 SpellChecker 코드 + return dictionary.contains(word); + } + + public List suggestions(String typo) { + // TODO 여기 SpellChecker 코드 + return dictionary.closeWordsTo(typo); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/springioc/App.java b/src/main/java/me/whiteship/chapter01/item05/springioc/App.java new file mode 100644 index 0000000..16290f7 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/springioc/App.java @@ -0,0 +1,13 @@ +package me.whiteship.chapter01.item05.springioc; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +public class App { + + public static void main(String[] args) { + ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); + SpellChecker spellChecker = applicationContext.getBean(SpellChecker.class); + spellChecker.isValid("test"); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/springioc/AppConfig.java b/src/main/java/me/whiteship/chapter01/item05/springioc/AppConfig.java new file mode 100644 index 0000000..efc1147 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/springioc/AppConfig.java @@ -0,0 +1,10 @@ +package me.whiteship.chapter01.item05.springioc; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackageClasses = AppConfig.class) +public class AppConfig { + +} diff --git a/src/main/java/me/whiteship/chapter01/item05/springioc/SpellChecker.java b/src/main/java/me/whiteship/chapter01/item05/springioc/SpellChecker.java new file mode 100644 index 0000000..fcec03a --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/springioc/SpellChecker.java @@ -0,0 +1,26 @@ +package me.whiteship.chapter01.item05.springioc; + +import me.whiteship.chapter01.item05.Dictionary; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class SpellChecker { + + private Dictionary dictionary; + + public SpellChecker(Dictionary dictionary) { + this.dictionary = dictionary; + } + + public boolean isValid(String word) { + // TODO 여기 SpellChecker 코드 + return dictionary.contains(word); + } + + public List suggestions(String typo) { + // TODO 여기 SpellChecker 코드 + return dictionary.closeWordsTo(typo); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/springioc/SpringDictionary.java b/src/main/java/me/whiteship/chapter01/item05/springioc/SpringDictionary.java new file mode 100644 index 0000000..948dd43 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/springioc/SpringDictionary.java @@ -0,0 +1,21 @@ +package me.whiteship.chapter01.item05.springioc; + +import me.whiteship.chapter01.item05.Dictionary; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class SpringDictionary implements Dictionary { + + @Override + public boolean contains(String word) { + System.out.println("contains " + word); + return false; + } + + @Override + public List closeWordsTo(String typo) { + return null; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item05/staticutils/SpellChecker.java b/src/main/java/me/whiteship/chapter01/item05/staticutils/SpellChecker.java new file mode 100644 index 0000000..73e17f2 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item05/staticutils/SpellChecker.java @@ -0,0 +1,23 @@ +package me.whiteship.chapter01.item05.staticutils; + +import me.whiteship.chapter01.item05.DefaultDictionary; +import me.whiteship.chapter01.item05.Dictionary; + +import java.util.List; + +public class SpellChecker { + + private static final Dictionary dictionary = new DefaultDictionary(); + + private SpellChecker() {} + + public static boolean isValid(String word) { + // TODO 여기 SpellChecker 코드 + return dictionary.contains(word); + } + + public static List suggestions(String typo) { + // TODO 여기 SpellChecker 코드 + return dictionary.closeWordsTo(typo); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item06/Client.java b/src/main/java/me/whiteship/chapter01/item06/Client.java new file mode 100644 index 0000000..248b6a2 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item06/Client.java @@ -0,0 +1,8 @@ +package me.whiteship.chapter01.item06; + +public class Client { + + public static void main(String[] args) { + Deprecation deprecation = new Deprecation("string"); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item06/Deprecation.java b/src/main/java/me/whiteship/chapter01/item06/Deprecation.java new file mode 100644 index 0000000..0f67d86 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item06/Deprecation.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter01.item06; + +public class Deprecation { + + /** + * @deprecated in favor of + * {@link #Deprecation(String)} + */ + @Deprecated(forRemoval = true, since = "1.2") + public Deprecation() { + } + + private String name; + + public Deprecation(String name) { + this.name = name; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item06/RegularExpression.java b/src/main/java/me/whiteship/chapter01/item06/RegularExpression.java new file mode 100644 index 0000000..3c99ecd --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item06/RegularExpression.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter01.item06; + +import java.util.regex.Pattern; + +public class RegularExpression { + + private static final Pattern SPLIT_PATTERN = Pattern.compile(","); + + public static void main(String[] args) { + long start = System.nanoTime(); + for (int j = 0; j < 10000; j++) { + String name = "keesun,whiteship"; + name.split(","); +// SPLIT_PATTERN.split(name); + } + System.out.println(System.nanoTime() - start); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item06/RomanNumerals.java b/src/main/java/me/whiteship/chapter01/item06/RomanNumerals.java new file mode 100644 index 0000000..f5a4dca --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item06/RomanNumerals.java @@ -0,0 +1,31 @@ +package me.whiteship.chapter01.item06; +import java.util.regex.Pattern; + +// 값비싼 객체를 재사용해 성능을 개선한다. (32쪽) +public class RomanNumerals { + // 코드 6-1 성능을 훨씬 더 끌어올릴 수 있다! + static boolean isRomanNumeralSlow(String s) { + return s.matches("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$"); + } + + // 코드 6-2 값비싼 객체를 재사용해 성능을 개선한다. + private static final Pattern ROMAN = Pattern.compile( + "^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$"); + + static boolean isRomanNumeralFast(String s) { + return ROMAN.matcher(s).matches(); + } + + public static void main(String[] args) { + boolean result = false; + long start = System.nanoTime(); + for (int j = 0; j < 100; j++) { + //TODO 성능 차이를 확인하려면 xxxSlow 메서드를 xxxFast 메서드로 바꿔 실행해보자. + result = isRomanNumeralSlow("MCMLXXVI"); + } + long end = System.nanoTime(); + System.out.println(end - start); + System.out.println(result); + } +} + diff --git a/src/main/java/me/whiteship/chapter01/item06/Strings.java b/src/main/java/me/whiteship/chapter01/item06/Strings.java new file mode 100644 index 0000000..af7f15c --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item06/Strings.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter01.item06; + +public class Strings { + + public static void main(String[] args) { + String hello = "hello"; + + //TODO 이 방법은 권장하지 않습니다. + String hello2 = new String("hello"); + + String hello3 = "hello"; + + System.out.println(hello == hello2); + System.out.println(hello.equals(hello2)); + System.out.println(hello == hello3); + System.out.println(hello.equals(hello3)); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item06/Sum.java b/src/main/java/me/whiteship/chapter01/item06/Sum.java new file mode 100644 index 0000000..cd71be4 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item06/Sum.java @@ -0,0 +1,19 @@ +package me.whiteship.chapter01.item06; + +public class Sum { + private static long sum() { + // TODO Long을 long으로 변경하여 실행해 보세요. + Long sum = 0L; + for (long i = 0; i <= Integer.MAX_VALUE; i++) + sum += i; + return sum; + } + + public static void main(String[] args) { + long start = System.nanoTime(); + long x = sum(); + long end = System.nanoTime(); + System.out.println((end - start) / 1_000_000. + " ms."); + System.out.println(x); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/cache/CacheKey.java b/src/main/java/me/whiteship/chapter01/item07/cache/CacheKey.java new file mode 100644 index 0000000..6ac4ee0 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/cache/CacheKey.java @@ -0,0 +1,37 @@ +package me.whiteship.chapter01.item07.cache; + +import java.time.LocalDateTime; + +public class CacheKey { + + private Integer value; + + private LocalDateTime created; + + public CacheKey(Integer value) { + this.value = value; + this.created = LocalDateTime.now(); + } + + @Override + public boolean equals(Object o) { + return this.value.equals(o); + } + + @Override + public int hashCode() { + return this.value.hashCode(); + } + + public LocalDateTime getCreated() { + return created; + } + + @Override + public String toString() { + return "CacheKey{" + + "value=" + value + + ", created=" + created + + '}'; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/cache/Post.java b/src/main/java/me/whiteship/chapter01/item07/cache/Post.java new file mode 100644 index 0000000..344a0f0 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/cache/Post.java @@ -0,0 +1,39 @@ +package me.whiteship.chapter01.item07.cache; + +public class Post { + + private Integer id; + + private String title; + + private String content; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + @Override + public void finalize() { + System.out.println("gc called"); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/cache/PostRepository.java b/src/main/java/me/whiteship/chapter01/item07/cache/PostRepository.java new file mode 100644 index 0000000..792923d --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/cache/PostRepository.java @@ -0,0 +1,29 @@ +package me.whiteship.chapter01.item07.cache; + +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; + +public class PostRepository { + + private Map cache; + + public PostRepository() { + this.cache = new WeakHashMap<>(); + } + + public Post getPostById(CacheKey key) { + if (cache.containsKey(key)) { + return cache.get(key); + } else { + // TODO DB에서 읽어오거나 REST API를 통해 읽어올 수 있습니다. + Post post = new Post(); + cache.put(key, post); + return post; + } + } + + public Map getCache() { + return cache; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/executor/ExecutorsExample.java b/src/main/java/me/whiteship/chapter01/item07/executor/ExecutorsExample.java new file mode 100644 index 0000000..d5ed3ad --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/executor/ExecutorsExample.java @@ -0,0 +1,31 @@ +package me.whiteship.chapter01.item07.executor; + +import me.whiteship.chapter01.item01.Product; + +import java.util.concurrent.*; + +public class ExecutorsExample { + + public static void main(String[] args) throws ExecutionException, InterruptedException { + ExecutorService service = Executors.newFixedThreadPool(10); + + Future submit = service.submit(new Task()); + + System.out.println(Thread.currentThread() + " hello"); + + System.out.println(submit.get()); + + service.shutdown(); + } + + static class Task implements Callable { + + @Override + public String call() throws Exception { + Thread.sleep(2000L); + return Thread.currentThread() + " world"; + } + } + + +} diff --git a/src/main/java/me/whiteship/chapter01/item07/listener/ChatRoom.java b/src/main/java/me/whiteship/chapter01/item07/listener/ChatRoom.java new file mode 100644 index 0000000..9561f7b --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/listener/ChatRoom.java @@ -0,0 +1,27 @@ +package me.whiteship.chapter01.item07.listener; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class ChatRoom { + + private List> users; + + public ChatRoom() { + this.users = new ArrayList<>(); + } + + public void addUser(User user) { + this.users.add(new WeakReference<>(user)); + } + + public void sendMessage(String message) { + users.forEach(wr -> Objects.requireNonNull(wr.get()).receive(message)); + } + + public List> getUsers() { + return users; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/listener/User.java b/src/main/java/me/whiteship/chapter01/item07/listener/User.java new file mode 100644 index 0000000..c721af8 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/listener/User.java @@ -0,0 +1,8 @@ +package me.whiteship.chapter01.item07.listener; + +public class User { + + public void receive(String message) { + System.out.println(message); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/optional/Channel.java b/src/main/java/me/whiteship/chapter01/item07/optional/Channel.java new file mode 100644 index 0000000..095618d --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/optional/Channel.java @@ -0,0 +1,17 @@ +package me.whiteship.chapter01.item07.optional; + +import java.util.Optional; +import java.util.OptionalLong; + +public class Channel { + + private int numOfSubscribers; + + public Optional defaultMemberShip() { + if (this.numOfSubscribers < 2000) { + return Optional.empty(); + } else { + return Optional.of(new MemberShip()); + } + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/optional/MemberShip.java b/src/main/java/me/whiteship/chapter01/item07/optional/MemberShip.java new file mode 100644 index 0000000..a384c43 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/optional/MemberShip.java @@ -0,0 +1,8 @@ +package me.whiteship.chapter01.item07.optional; + +public class MemberShip { + + public String hello() { + return "hello"; + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/reference/BigObject.java b/src/main/java/me/whiteship/chapter01/item07/reference/BigObject.java new file mode 100644 index 0000000..41cab6e --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/reference/BigObject.java @@ -0,0 +1,4 @@ +package me.whiteship.chapter01.item07.reference; + +public class BigObject { +} diff --git a/src/main/java/me/whiteship/chapter01/item07/reference/BigObjectReference.java b/src/main/java/me/whiteship/chapter01/item07/reference/BigObjectReference.java new file mode 100644 index 0000000..faa311a --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/reference/BigObjectReference.java @@ -0,0 +1,15 @@ +package me.whiteship.chapter01.item07.reference; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; + +public class BigObjectReference extends PhantomReference { + + public BigObjectReference(BigObject referent, ReferenceQueue q) { + super(referent, q); + } + + public void cleanUp() { + System.out.println("clean up"); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/reference/PhantomReferenceExample.java b/src/main/java/me/whiteship/chapter01/item07/reference/PhantomReferenceExample.java new file mode 100644 index 0000000..a025ccc --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/reference/PhantomReferenceExample.java @@ -0,0 +1,28 @@ +package me.whiteship.chapter01.item07.reference; + +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; + +public class PhantomReferenceExample { + + public static void main(String[] args) throws InterruptedException { + BigObject strong = new BigObject(); + ReferenceQueue rq = new ReferenceQueue<>(); + + BigObjectReference phantom = new BigObjectReference<>(strong, rq); + strong = null; + + System.gc(); + Thread.sleep(3000L); + + // TODO 팬텀은 유령이니까.. + // 죽었지만.. 사라지진 않고 큐에 들어갑니다. + System.out.println(phantom.isEnqueued()); + + Reference reference = rq.poll(); + BigObjectReference bigObjectCleaner = (BigObjectReference) reference; + bigObjectCleaner.cleanUp(); + reference.clear(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/reference/SoftReferenceExample.java b/src/main/java/me/whiteship/chapter01/item07/reference/SoftReferenceExample.java new file mode 100644 index 0000000..a89393e --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/reference/SoftReferenceExample.java @@ -0,0 +1,19 @@ +package me.whiteship.chapter01.item07.reference; + +import java.lang.ref.SoftReference; + +public class SoftReferenceExample { + + public static void main(String[] args) throws InterruptedException { + Object strong = new Object(); + SoftReference soft = new SoftReference<>(strong); + strong = null; + + System.gc(); + Thread.sleep(3000L); + + // TODO 거의 안 없어집니다. + // 왜냐면 메모리가 충분해서.. 굳이 제거할 필요가 없으니까요. + System.out.println(soft.get()); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/reference/WeakReferenceExample.java b/src/main/java/me/whiteship/chapter01/item07/reference/WeakReferenceExample.java new file mode 100644 index 0000000..32a5d70 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/reference/WeakReferenceExample.java @@ -0,0 +1,19 @@ +package me.whiteship.chapter01.item07.reference; + +import java.lang.ref.WeakReference; + +public class WeakReferenceExample { + + public static void main(String[] args) throws InterruptedException { + Object strong = new Object(); + WeakReference weak = new WeakReference<>(strong); + strong = null; + + System.gc(); + Thread.sleep(3000L); + + // TODO 거의 없어집니다. + // 왜냐면 약하니까(?)... + System.out.println(weak.get()); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item07/stack/EmptyStackException.java b/src/main/java/me/whiteship/chapter01/item07/stack/EmptyStackException.java new file mode 100644 index 0000000..b6147c4 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/stack/EmptyStackException.java @@ -0,0 +1,5 @@ +package me.whiteship.chapter01.item07.stack; + +// (36쪽의 Stack 코드에서 던지는 예외) +public class EmptyStackException extends IllegalStateException { +} diff --git a/src/main/java/me/whiteship/chapter01/item07/stack/Stack.java b/src/main/java/me/whiteship/chapter01/item07/stack/Stack.java new file mode 100644 index 0000000..98618aa --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item07/stack/Stack.java @@ -0,0 +1,52 @@ +package me.whiteship.chapter01.item07.stack; + +import java.util.Arrays; + +// 코드 7-1 메모리 누수가 일어나는 위치는 어디인가? (36쪽) +public class Stack { + private Object[] elements; + private int size = 0; + private static final int DEFAULT_INITIAL_CAPACITY = 16; + + public Stack() { + elements = new Object[DEFAULT_INITIAL_CAPACITY]; + } + + public void push(Object e) { + ensureCapacity(); + elements[size++] = e; + } + +// public Object pop() { +// if (size == 0) +// throw new EmptyStackException(); +// return elements[--size]; +// } + + /** + * 원소를 위한 공간을 적어도 하나 이상 확보한다. + * 배열 크기를 늘려야 할 때마다 대략 두 배씩 늘린다. + */ + private void ensureCapacity() { + if (elements.length == size) + elements = Arrays.copyOf(elements, 2 * size + 1); + } + + // 코드 7-2 제대로 구현한 pop 메서드 (37쪽) + public Object pop() { + if (size == 0) + throw new EmptyStackException(); + Object result = elements[--size]; + elements[size] = null; // 다 쓴 참조 해제 + return result; + } + + public static void main(String[] args) { + Stack stack = new Stack(); + for (String arg : args) + stack.push(arg); + + while (true) + System.err.println(stack.pop()); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item08/autoclosable/App.java b/src/main/java/me/whiteship/chapter01/item08/autoclosable/App.java new file mode 100644 index 0000000..c234747 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/autoclosable/App.java @@ -0,0 +1,11 @@ +package me.whiteship.chapter01.item08.autoclosable; + +public class App { + + public static void main(String[] args) { + try(AutoClosableIsGood good = new AutoClosableIsGood("")) { + // TODO 자원 반납 처리가 됨. + + } + } +} diff --git a/src/main/java/me/whiteship/chapter01/item08/autoclosable/AutoClosableIsGood.java b/src/main/java/me/whiteship/chapter01/item08/autoclosable/AutoClosableIsGood.java new file mode 100644 index 0000000..bf9f931 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/autoclosable/AutoClosableIsGood.java @@ -0,0 +1,25 @@ +package me.whiteship.chapter01.item08.autoclosable; + +import java.io.*; + +public class AutoClosableIsGood implements Closeable { + + private BufferedReader reader; + + public AutoClosableIsGood(String path) { + try { + this.reader = new BufferedReader(new FileReader(path)); + } catch (FileNotFoundException e) { + throw new IllegalArgumentException(path); + } + } + + @Override + public void close() { + try { + reader.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/me/whiteship/chapter01/item08/cleaner/BigObject.java b/src/main/java/me/whiteship/chapter01/item08/cleaner/BigObject.java new file mode 100644 index 0000000..731d302 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/cleaner/BigObject.java @@ -0,0 +1,27 @@ +package me.whiteship.chapter01.item08.cleaner; + +import java.util.List; + +public class BigObject { + + private List resource; + + public BigObject(List resource) { + this.resource = resource; + } + + public static class ResourceCleaner implements Runnable { + + private List resourceToClean; + + public ResourceCleaner(List resourceToClean) { + this.resourceToClean = resourceToClean; + } + + @Override + public void run() { + resourceToClean = null; + System.out.println("cleaned up."); + } + } +} diff --git a/src/main/java/me/whiteship/chapter01/item08/cleaner/CleanerIsNotGood.java b/src/main/java/me/whiteship/chapter01/item08/cleaner/CleanerIsNotGood.java new file mode 100644 index 0000000..fb9736b --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/cleaner/CleanerIsNotGood.java @@ -0,0 +1,21 @@ +package me.whiteship.chapter01.item08.cleaner; + +import java.lang.ref.Cleaner; +import java.util.ArrayList; +import java.util.List; + +public class CleanerIsNotGood { + + public static void main(String[] args) throws InterruptedException { + Cleaner cleaner = Cleaner.create(); + + List resourceToCleanUp = new ArrayList<>(); + BigObject bigObject = new BigObject(resourceToCleanUp); + cleaner.register(bigObject, new BigObject.ResourceCleaner(resourceToCleanUp)); + + bigObject = null; + System.gc(); + Thread.sleep(3000L); + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Adult.java b/src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Adult.java new file mode 100644 index 0000000..475d68d --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Adult.java @@ -0,0 +1,10 @@ +package me.whiteship.chapter01.item08.cleaner_as_a_safetynet; + +// cleaner 안전망을 갖춘 자원을 제대로 활용하는 클라이언트 (45쪽) +public class Adult { + public static void main(String[] args) { + try (Room myRoom = new Room(7)) { + System.out.println("안녕~"); + } + } +} diff --git a/src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Room.java b/src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Room.java new file mode 100644 index 0000000..c8046ec --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Room.java @@ -0,0 +1,38 @@ +package me.whiteship.chapter01.item08.cleaner_as_a_safetynet; + +import java.lang.ref.Cleaner; + +// 코드 8-1 cleaner를 안전망으로 활용하는 AutoCloseable 클래스 (44쪽) +public class Room implements AutoCloseable { + private static final Cleaner cleaner = Cleaner.create(); + + // 청소가 필요한 자원. 절대 Room을 참조해서는 안 된다! + private static class State implements Runnable { + int numJunkPiles; // Number of junk piles in this room + + State(int numJunkPiles) { + this.numJunkPiles = numJunkPiles; + } + + // close 메서드나 cleaner가 호출한다. + @Override public void run() { + System.out.println("Cleaning room"); + numJunkPiles = 0; + } + } + + // 방의 상태. cleanable과 공유한다. + private final State state; + + // cleanable 객체. 수거 대상이 되면 방을 청소한다. + private final Cleaner.Cleanable cleanable; + + public Room(int numJunkPiles) { + state = new State(numJunkPiles); + cleanable = cleaner.register(this, state); + } + + @Override public void close() { + cleanable.clean(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Teenager.java b/src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Teenager.java new file mode 100644 index 0000000..0cd7021 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/cleaner_as_a_safetynet/Teenager.java @@ -0,0 +1,14 @@ +package me.whiteship.chapter01.item08.cleaner_as_a_safetynet; + +// cleaner 안전망을 갖춘 자원을 제대로 활용하지 못하는 클라이언트 (45쪽) +public class Teenager { + + public static void main(String[] args) { + new Room(99); + System.out.println("Peace out"); + + // 다음 줄의 주석을 해제한 후 동작을 다시 확인해보자. + // 단, 가비지 컬렉러를 강제로 호출하는 이런 방식에 의존해서는 절대 안 된다! + System.gc(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item08/finalizer/App.java b/src/main/java/me/whiteship/chapter01/item08/finalizer/App.java new file mode 100644 index 0000000..a8ac0cc --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/finalizer/App.java @@ -0,0 +1,36 @@ +package me.whiteship.chapter01.item08.finalizer; + +import com.sun.management.UnixOperatingSystemMXBean; +import org.springframework.jmx.support.MBeanServerFactoryBean; + +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.ref.ReferenceQueue; +import java.lang.reflect.Field; + +public class App { + + /** + * 코드 참고 https://www.baeldung.com/java-finalize + */ + public static void main(String[] args) throws InterruptedException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + int i = 0; + while(true) { + i++; + new FinalizerIsBad(); + + if ((i % 1_000_000) == 0) { + Class finalizerClass = Class.forName("java.lang.ref.Finalizer"); + Field queueStaticField = finalizerClass.getDeclaredField("queue"); + queueStaticField.setAccessible(true); + ReferenceQueue referenceQueue = (ReferenceQueue) queueStaticField.get(null); + + Field queueLengthField = ReferenceQueue.class.getDeclaredField("queueLength"); + queueLengthField.setAccessible(true); + long queueLength = (long) queueLengthField.get(referenceQueue); + System.out.format("There are %d references in the queue%n", queueLength); + } + } + } +} diff --git a/src/main/java/me/whiteship/chapter01/item08/finalizer/FinalizerIsBad.java b/src/main/java/me/whiteship/chapter01/item08/finalizer/FinalizerIsBad.java new file mode 100644 index 0000000..04c5c20 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/finalizer/FinalizerIsBad.java @@ -0,0 +1,9 @@ +package me.whiteship.chapter01.item08.finalizer; + +public class FinalizerIsBad { + + @Override + protected void finalize() throws Throwable { + System.out.print(""); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item08/finalizer_attack/Account.java b/src/main/java/me/whiteship/chapter01/item08/finalizer_attack/Account.java new file mode 100644 index 0000000..fc04278 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/finalizer_attack/Account.java @@ -0,0 +1,21 @@ +package me.whiteship.chapter01.item08.finalizer_attack; + +import java.math.BigDecimal; + +public class Account { + + private String accountId; + + public Account(String accountId) { + this.accountId = accountId; + + if (accountId.equals("푸틴")) { + throw new IllegalArgumentException("푸틴은 계정을 막습니다."); + } + } + + public void transfer(BigDecimal amount, String to) { + System.out.printf("transfer %f from %s to %s\n", amount, accountId, to); + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item08/finalizer_attack/BrokenAccount.java b/src/main/java/me/whiteship/chapter01/item08/finalizer_attack/BrokenAccount.java new file mode 100644 index 0000000..886e192 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/finalizer_attack/BrokenAccount.java @@ -0,0 +1,16 @@ +package me.whiteship.chapter01.item08.finalizer_attack; + +import java.math.BigDecimal; + +public class BrokenAccount extends Account { + + public BrokenAccount(String accountId) { + super(accountId); + } + + @Override + protected void finalize() throws Throwable { + this.transfer(BigDecimal.valueOf(100), "keesun"); + } +} + diff --git a/src/main/java/me/whiteship/chapter01/item08/outerclass/LambdaExample.java b/src/main/java/me/whiteship/chapter01/item08/outerclass/LambdaExample.java new file mode 100644 index 0000000..de58cb9 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/outerclass/LambdaExample.java @@ -0,0 +1,22 @@ +package me.whiteship.chapter01.item08.outerclass; + +import java.lang.reflect.Field; + +public class LambdaExample { + + private int value = 10; + + private Runnable instanceLambda = () -> { + System.out.println(value); + }; + + public static void main(String[] args) { + LambdaExample example = new LambdaExample(); + Field[] declaredFields = example.instanceLambda.getClass().getDeclaredFields(); + for (Field field : declaredFields) { + System.out.println("field type: " + field.getType()); + System.out.println("field name: " + field.getName()); + } + } + +} diff --git a/src/main/java/me/whiteship/chapter01/item08/outerclass/OuterClass.java b/src/main/java/me/whiteship/chapter01/item08/outerclass/OuterClass.java new file mode 100644 index 0000000..d62bcf4 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item08/outerclass/OuterClass.java @@ -0,0 +1,35 @@ +package me.whiteship.chapter01.item08.outerclass; + +import java.lang.reflect.Field; + +public class OuterClass { + + private void hi() { + + } + + class InnerClass { + + public void hello() { + OuterClass.this.hi(); + } + + } + + public static void main(String[] args) { + OuterClass outerClass = new OuterClass(); + InnerClass innerClass = outerClass.new InnerClass(); + + System.out.println(innerClass); + + outerClass.printFiled(); + } + + private void printFiled() { + Field[] declaredFields = InnerClass.class.getDeclaredFields(); + for(Field field : declaredFields) { + System.out.println("field type:" + field.getType()); + System.out.println("field name:" + field.getName()); + } + } +} diff --git a/src/main/java/me/whiteship/chapter01/item09/puzzler/Copy.java b/src/main/java/me/whiteship/chapter01/item09/puzzler/Copy.java new file mode 100644 index 0000000..c6b1dfe --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item09/puzzler/Copy.java @@ -0,0 +1,37 @@ +package me.whiteship.chapter01.item09.puzzler; + +import java.io.*; + +public class Copy { + private static final int BUFFER_SIZE = 8 * 1024; + + // 코드 9-2 자원이 둘 이상이면 try-finally 방식은 너무 지저분하다! (47쪽) + static void copy(String src, String dst) throws IOException { + InputStream in = new FileInputStream(src); + OutputStream out = new FileOutputStream(dst); + try { + byte[] buf = new byte[BUFFER_SIZE]; + int n; + while ((n = in.read(buf)) >= 0) + out.write(buf, 0, n); + } finally { + try { + out.close(); + } catch (IOException e) { + // TODO 이렇게 하면 되는거 아닌가? + } + + try { + in.close(); + } catch (IOException e) { + // TODO 안전한가? + } + } + } + + public static void main(String[] args) throws IOException { + String src = args[0]; + String dst = args[1]; + copy(src, dst); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item09/suppress/BadBufferedReader.java b/src/main/java/me/whiteship/chapter01/item09/suppress/BadBufferedReader.java new file mode 100644 index 0000000..e532ce8 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item09/suppress/BadBufferedReader.java @@ -0,0 +1,23 @@ +package me.whiteship.chapter01.item09.suppress; + +import java.io.*; + +public class BadBufferedReader extends BufferedReader { + public BadBufferedReader(Reader in, int sz) { + super(in, sz); + } + + public BadBufferedReader(Reader in) { + super(in); + } + + @Override + public String readLine() throws IOException { + throw new CharConversionException(); + } + + @Override + public void close() throws IOException { + throw new StreamCorruptedException(); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item09/suppress/TopLine.java b/src/main/java/me/whiteship/chapter01/item09/suppress/TopLine.java new file mode 100644 index 0000000..160fa27 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item09/suppress/TopLine.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter01.item09.suppress; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class TopLine { + // 코드 9-1 try-finally - 더 이상 자원을 회수하는 최선의 방책이 아니다! (47쪽) + static String firstLineOfFile(String path) throws IOException { + try(BufferedReader br = new BadBufferedReader(new FileReader(path))) { + return br.readLine(); + } + } + + public static void main(String[] args) throws IOException { + System.out.println(firstLineOfFile("pom.xml")); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item09/tryfinally/Copy.java b/src/main/java/me/whiteship/chapter01/item09/tryfinally/Copy.java new file mode 100644 index 0000000..63ae3dd --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item09/tryfinally/Copy.java @@ -0,0 +1,31 @@ +package me.whiteship.chapter01.item09.tryfinally; + +import java.io.*; + +public class Copy { + private static final int BUFFER_SIZE = 8 * 1024; + + // 코드 9-2 자원이 둘 이상이면 try-finally 방식은 너무 지저분하다! (47쪽) + static void copy(String src, String dst) throws IOException { + InputStream in = new FileInputStream(src); + try { + OutputStream out = new FileOutputStream(dst); + try { + byte[] buf = new byte[BUFFER_SIZE]; + int n; + while ((n = in.read(buf)) >= 0) + out.write(buf, 0, n); + } finally { + out.close(); + } + } finally { + in.close(); + } + } + + public static void main(String[] args) throws IOException { + String src = args[0]; + String dst = args[1]; + copy(src, dst); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item09/tryfinally/TopLine.java b/src/main/java/me/whiteship/chapter01/item09/tryfinally/TopLine.java new file mode 100644 index 0000000..52c55e8 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item09/tryfinally/TopLine.java @@ -0,0 +1,22 @@ +package me.whiteship.chapter01.item09.tryfinally; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class TopLine { + // 코드 9-1 try-finally - 더 이상 자원을 회수하는 최선의 방책이 아니다! (47쪽) + static String firstLineOfFile(String path) throws IOException { + BufferedReader br = new BufferedReader(new FileReader(path)); + try { + return br.readLine(); + } finally { + br.close(); + } + } + + public static void main(String[] args) throws IOException { + String path = args[0]; + System.out.println(firstLineOfFile(path)); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item09/trywithresources/Copy.java b/src/main/java/me/whiteship/chapter01/item09/trywithresources/Copy.java new file mode 100644 index 0000000..87083b6 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item09/trywithresources/Copy.java @@ -0,0 +1,24 @@ +package me.whiteship.chapter01.item09.trywithresources; + +import java.io.*; + +public class Copy { + private static final int BUFFER_SIZE = 8 * 1024; + + // 코드 9-4 복수의 자원을 처리하는 try-with-resources - 짧고 매혹적이다! (49쪽) + static void copy(String src, String dst) throws IOException { + try (InputStream in = new FileInputStream(src); + OutputStream out = new FileOutputStream(dst)) { + byte[] buf = new byte[BUFFER_SIZE]; + int n; + while ((n = in.read(buf)) >= 0) + out.write(buf, 0, n); + } + } + + public static void main(String[] args) throws IOException { + String src = args[0]; + String dst = args[1]; + copy(src, dst); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item09/trywithresources/TopLine.java b/src/main/java/me/whiteship/chapter01/item09/trywithresources/TopLine.java new file mode 100644 index 0000000..d088f44 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item09/trywithresources/TopLine.java @@ -0,0 +1,21 @@ +package me.whiteship.chapter01.item09.trywithresources; + + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class TopLine { + // 코드 9-3 try-with-resources - 자원을 회수하는 최선책! (48쪽) + static String firstLineOfFile(String path) throws IOException { + try (BufferedReader br = new BufferedReader( + new FileReader(path))) { + return br.readLine(); + } + } + + public static void main(String[] args) throws IOException { + String path = args[0]; + System.out.println(firstLineOfFile(path)); + } +} diff --git a/src/main/java/me/whiteship/chapter01/item09/trywithresources/TopLineWithDefault.java b/src/main/java/me/whiteship/chapter01/item09/trywithresources/TopLineWithDefault.java new file mode 100644 index 0000000..bbd8d39 --- /dev/null +++ b/src/main/java/me/whiteship/chapter01/item09/trywithresources/TopLineWithDefault.java @@ -0,0 +1,23 @@ +package me.whiteship.chapter01.item09.trywithresources; + + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class TopLineWithDefault { + // 코드 9-5 try-with-resources를 catch 절과 함께 쓰는 모습 (49쪽) + static String firstLineOfFile(String path, String defaultVal) { + try (BufferedReader br = new BufferedReader( + new FileReader(path))) { + return br.readLine(); + } catch (IOException e) { + return defaultVal; + } + } + + public static void main(String[] args) throws IOException { + String path = args[0]; + System.out.println(firstLineOfFile(path, "Toppy McTopFace")); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/CaseInsensitiveString.java b/src/main/java/me/whiteship/chapter02/item10/CaseInsensitiveString.java new file mode 100644 index 0000000..7d682d7 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/CaseInsensitiveString.java @@ -0,0 +1,44 @@ +package me.whiteship.chapter02.item10; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +// 코드 10-1 잘못된 코드 - 대칭성 위배! (54-55쪽) +public final class CaseInsensitiveString { + private final String s; + + public CaseInsensitiveString(String s) { + this.s = Objects.requireNonNull(s); + } + +// 대칭성 위배! + @Override public boolean equals(Object o) { + if (o instanceof CaseInsensitiveString) + return s.equalsIgnoreCase( + ((CaseInsensitiveString) o).s); + if (o instanceof String) // 한 방향으로만 작동한다! + return s.equalsIgnoreCase((String) o); + return false; + } + + // 문제 시연 (55쪽) + public static void main(String[] args) { + CaseInsensitiveString cis = new CaseInsensitiveString("Polish"); +// CaseInsensitiveString cis2 = new CaseInsensitiveString("polish"); + String polish = "polish"; + System.out.println(cis.equals(polish)); +// System.out.println(cis2.equals(cis)); + + List list = new ArrayList<>(); + list.add(cis); + + System.out.println(list.contains(polish)); + } + + // 수정한 equals 메서드 (56쪽) +// @Override public boolean equals(Object o) { +// return o instanceof CaseInsensitiveString && +// ((CaseInsensitiveString) o).s.equalsIgnoreCase(s); +// } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/Color.java b/src/main/java/me/whiteship/chapter02/item10/Color.java new file mode 100644 index 0000000..1d3e793 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/Color.java @@ -0,0 +1,3 @@ +package me.whiteship.chapter02.item10; + +public enum Color { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET } diff --git a/src/main/java/me/whiteship/chapter02/item10/EqualsInJava.java b/src/main/java/me/whiteship/chapter02/item10/EqualsInJava.java new file mode 100644 index 0000000..ecf3848 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/EqualsInJava.java @@ -0,0 +1,24 @@ +package me.whiteship.chapter02.item10; + +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.Timestamp; +import java.util.Date; + +public class EqualsInJava extends Object { + + public static void main(String[] args) throws MalformedURLException { + long time = System.currentTimeMillis(); + Timestamp timestamp = new Timestamp(time); + Date date = new Date(time); + + // 대칭성 위배! P60 + System.out.println(date.equals(timestamp)); + System.out.println(timestamp.equals(date)); + + // 일관성 위배 가능성 있음. P61 + URL google1 = new URL("https", "about.google", "/products/"); + URL google2 = new URL("https", "about.google", "/products/"); + System.out.println(google1.equals(google2)); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/PhoneNumber.java b/src/main/java/me/whiteship/chapter02/item10/PhoneNumber.java new file mode 100644 index 0000000..cbd3b58 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/PhoneNumber.java @@ -0,0 +1,30 @@ +package me.whiteship.chapter02.item10; + +// 코드 10-6 전형적인 equals 메서드의 예 (64쪽) +public final class PhoneNumber { + private final short areaCode, prefix, lineNum; + + public PhoneNumber(int areaCode, int prefix, int lineNum) { + this.areaCode = rangeCheck(areaCode, 999, "지역코드"); + this.prefix = rangeCheck(prefix, 999, "프리픽스"); + this.lineNum = rangeCheck(lineNum, 9999, "가입자 번호"); + } + + private static short rangeCheck(int val, int max, String arg) { + if (val < 0 || val > max) + throw new IllegalArgumentException(arg + ": " + val); + return (short) val; + } + + @Override public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof PhoneNumber)) + return false; + PhoneNumber pn = (PhoneNumber)o; + return pn.lineNum == lineNum && pn.prefix == prefix + && pn.areaCode == areaCode; + } + + // 나머지 코드는 생략 - hashCode 메서드는 꼭 필요하다(아이템 11)! +} diff --git a/src/main/java/me/whiteship/chapter02/item10/Point.java b/src/main/java/me/whiteship/chapter02/item10/Point.java new file mode 100644 index 0000000..eb25a78 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/Point.java @@ -0,0 +1,49 @@ +package me.whiteship.chapter02.item10; + +import java.util.ArrayList; +import java.util.List; + +// 단순한 불변 2차원 정수 점(point) 클래스 (56쪽) +public class Point { + + private final int x; + private final int y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + @Override public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof Point)) { + return false; + } + + Point p = (Point) o; + return p.x == x && p.y == y; + } + + public static void main(String[] args) { + Point point = new Point(1, 2); + List points = new ArrayList<>(); + points.add(point); + System.out.println(points.contains(new Point(1, 2))); + } + + // 잘못된 코드 - 리스코프 치환 원칙 위배! (59쪽) +// @Override public boolean equals(Object o) { +// if (o == null || o.getClass() != getClass()) +// return false; +// Point p = (Point) o; +// return p.x == x && p.y == y; +// } + + // 아이템 11 참조 + @Override public int hashCode() { + return 31 * x + y; + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/autovalue/AutoValueTest.java b/src/main/java/me/whiteship/chapter02/item10/autovalue/AutoValueTest.java new file mode 100644 index 0000000..dcb73bd --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/autovalue/AutoValueTest.java @@ -0,0 +1,9 @@ +package me.whiteship.chapter02.item10.autovalue; + +public class AutoValueTest { + + public static void main(String[] args) { + Point point = Point.create(1, 2); + System.out.println(point.equals(Point.create(1, 2))); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/autovalue/Point.java b/src/main/java/me/whiteship/chapter02/item10/autovalue/Point.java new file mode 100644 index 0000000..f8c0727 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/autovalue/Point.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter02.item10.autovalue; + +import com.google.auto.value.AutoValue; + +/** + * AutoValue 참고 + * + * https://github.com/google/auto/blob/master/value/userguide/index.md + */ +@AutoValue +abstract class Point { + static Point create(int x, int y) { + return new AutoValue_Point(x, y); + } + + abstract int x(); + abstract int y(); +} diff --git a/src/main/java/me/whiteship/chapter02/item10/composition/ColorPoint.java b/src/main/java/me/whiteship/chapter02/item10/composition/ColorPoint.java new file mode 100644 index 0000000..be5e4f2 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/composition/ColorPoint.java @@ -0,0 +1,36 @@ +package me.whiteship.chapter02.item10.composition; + + +import me.whiteship.chapter02.item10.Color; +import me.whiteship.chapter02.item10.Point; + +import java.util.Objects; + +// 코드 10-5 equals 규약을 지키면서 값 추가하기 (60쪽) +public class ColorPoint { + private final Point point; + private final Color color; + + public ColorPoint(int x, int y, Color color) { + point = new Point(x, y); + this.color = Objects.requireNonNull(color); + } + + /** + * 이 ColorPoint의 Point 뷰를 반환한다. + */ + public Point asPoint() { + return point; + } + + @Override public boolean equals(Object o) { + if (!(o instanceof ColorPoint)) + return false; + ColorPoint cp = (ColorPoint) o; + return cp.point.equals(point) && cp.color.equals(color); + } + + @Override public int hashCode() { + return 31 * point.hashCode() + color.hashCode(); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/inheritance/ColorPoint.java b/src/main/java/me/whiteship/chapter02/item10/inheritance/ColorPoint.java new file mode 100644 index 0000000..598124e --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/inheritance/ColorPoint.java @@ -0,0 +1,48 @@ +package me.whiteship.chapter02.item10.inheritance; + +import me.whiteship.chapter02.item10.Color; +import me.whiteship.chapter02.item10.Point; + +// Point에 값 컴포넌트(color)를 추가 (56쪽) +public class ColorPoint extends Point { + private final Color color; + + public ColorPoint(int x, int y, Color color) { + super(x, y); + this.color = color; + } + + // 코드 10-2 잘못된 코드 - 대칭성 위배! (57쪽) +// @Override public boolean equals(Object o) { +// if (!(o instanceof ColorPoint)) +// return false; +// return super.equals(o) && ((ColorPoint) o).color == color; +// } + +// // 코드 10-3 잘못된 코드 - 추이성 위배! (57쪽) + @Override public boolean equals(Object o) { + if (!(o instanceof Point)) + return false; + + // o가 일반 Point면 색상을 무시하고 비교한다. + if (!(o instanceof ColorPoint)) + return o.equals(this); + + // o가 ColorPoint면 색상까지 비교한다. + return super.equals(o) && ((ColorPoint) o).color == color; + } + + public static void main(String[] args) { + // 첫 번째 equals 메서드(코드 10-2)는 대칭성을 위배한다. (57쪽) +// Point p = new Point(1, 2); +// ColorPoint cp = new ColorPoint(1, 2, Color.RED); +// System.out.println(p.equals(cp) + " " + cp.equals(p)); + + // 두 번째 equals 메서드(코드 10-3)는 추이성을 위배한다. (57쪽) + ColorPoint p1 = new ColorPoint(1, 2, Color.RED); + Point p2 = new Point(1, 2); + ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE); + System.out.printf("%s %s %s%n", + p1.equals(p2), p2.equals(p3), p1.equals(p3)); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/inheritance/CounterPoint.java b/src/main/java/me/whiteship/chapter02/item10/inheritance/CounterPoint.java new file mode 100644 index 0000000..b26cdad --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/inheritance/CounterPoint.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter02.item10.inheritance; + + +import me.whiteship.chapter02.item10.Point; + +import java.util.concurrent.atomic.AtomicInteger; + +// Point의 평범한 하위 클래스 - 값 컴포넌트를 추가하지 않았다. (59쪽) +public class CounterPoint extends Point { + private static final AtomicInteger counter = + new AtomicInteger(); + + public CounterPoint(int x, int y) { + super(x, y); + counter.incrementAndGet(); + } + public static int numberCreated() { return counter.get(); } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/inheritance/CounterPointTest.java b/src/main/java/me/whiteship/chapter02/item10/inheritance/CounterPointTest.java new file mode 100644 index 0000000..7c2c3fe --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/inheritance/CounterPointTest.java @@ -0,0 +1,30 @@ +package me.whiteship.chapter02.item10.inheritance; + + +import me.whiteship.chapter02.item10.Color; +import me.whiteship.chapter02.item10.Point; + +import java.util.Set; + +// CounterPoint를 Point로 사용하는 테스트 프로그램 +public class CounterPointTest { + // 단위 원 안의 모든 점을 포함하도록 unitCircle을 초기화한다. (58쪽) + private static final Set unitCircle = Set.of( + new Point( 1, 0), new Point( 0, 1), + new Point(-1, 0), new Point( 0, -1)); + + public static boolean onUnitCircle(Point p) { + return unitCircle.contains(p); + } + + public static void main(String[] args) { + Point p1 = new Point(1, 0); + Point p2 = new CounterPoint(1, 0); + + // true를 출력한다. + System.out.println(onUnitCircle(p1)); + + // true를 출력해야 하지만, Point의 equals가 getClass를 사용해 작성되었다면 그렇지 않다. + System.out.println(onUnitCircle(p2)); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/inheritance/SmellPoint.java b/src/main/java/me/whiteship/chapter02/item10/inheritance/SmellPoint.java new file mode 100644 index 0000000..e2beff3 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/inheritance/SmellPoint.java @@ -0,0 +1,25 @@ +package me.whiteship.chapter02.item10.inheritance; + +import me.whiteship.chapter02.item10.Point; + +public class SmellPoint extends Point { + + private String smell; + + public SmellPoint(int x, int y, String smell) { + super(x, y); + this.smell = smell; + } + + @Override public boolean equals(Object o) { + if (!(o instanceof Point)) + return false; + + // o가 일반 Point면 색상을 무시하고 비교한다. + if (!(o instanceof SmellPoint)) + return o.equals(this); + + // o가 ColorPoint면 색상까지 비교한다. + return super.equals(o) && ((SmellPoint) o).smell.equals(smell); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/inheritance/SmellPointTest.java b/src/main/java/me/whiteship/chapter02/item10/inheritance/SmellPointTest.java new file mode 100644 index 0000000..a7c1f8a --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/inheritance/SmellPointTest.java @@ -0,0 +1,16 @@ +package me.whiteship.chapter02.item10.inheritance; + +import me.whiteship.chapter02.item10.Color; + +public class SmellPointTest { + + /** + * TODO -Xss10M + * @param args + */ + public static void main(String[] args) { + SmellPoint p1 = new SmellPoint(1, 0, "sweat"); + ColorPoint p2 = new ColorPoint(1, 0, Color.RED); + p1.equals(p2); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/lombok/LombokTest.java b/src/main/java/me/whiteship/chapter02/item10/lombok/LombokTest.java new file mode 100644 index 0000000..c17e031 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/lombok/LombokTest.java @@ -0,0 +1,9 @@ +package me.whiteship.chapter02.item10.lombok; + +public class LombokTest { + + public static void main(String[] args) { + Point point = new Point(1, 2); + System.out.println(point.equals(new Point(1, 2))); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item10/lombok/Point.java b/src/main/java/me/whiteship/chapter02/item10/lombok/Point.java new file mode 100644 index 0000000..30b8a8d --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/lombok/Point.java @@ -0,0 +1,21 @@ +package me.whiteship.chapter02.item10.lombok; + +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * https://projectlombok.org/features/EqualsAndHashCode + * https://projectlombok.org/features/ToString + */ +@EqualsAndHashCode +@ToString +public class Point { + private final int x; + private final int y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + +} diff --git a/src/main/java/me/whiteship/chapter02/item10/record/Point.java b/src/main/java/me/whiteship/chapter02/item10/record/Point.java new file mode 100644 index 0000000..a0f0fe1 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/record/Point.java @@ -0,0 +1,5 @@ +//package me.whiteship.chapter02.item10.record; +// +//public record Point(int x, int y) { +// +//} diff --git a/src/main/java/me/whiteship/chapter02/item10/record/PointTest.java b/src/main/java/me/whiteship/chapter02/item10/record/PointTest.java new file mode 100644 index 0000000..be58a3a --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item10/record/PointTest.java @@ -0,0 +1,14 @@ +//package me.whiteship.chapter02.item10.record; +// +//public class PointTest { +// +// public static void main(String[] args) { +// Point p1 = new Point(1, 0); +// Point p2 = new Point(1, 0); +// System.out.println(p1.equals(p2)); +// System.out.println(p1); +// +// System.out.println(p1.x()); +// System.out.println(p1.y()); +// } +//} diff --git a/src/main/java/me/whiteship/chapter02/item11/guava/PhoneNumber.java b/src/main/java/me/whiteship/chapter02/item11/guava/PhoneNumber.java new file mode 100644 index 0000000..1452447 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item11/guava/PhoneNumber.java @@ -0,0 +1,55 @@ +package me.whiteship.chapter02.item11.guava; + +import com.google.common.hash.Funnel; +import com.google.common.hash.Hashing; +import com.google.common.hash.PrimitiveSink; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +// equals를 재정의하면 hashCode로 재정의해야 함을 보여준다. (70-71쪽) +public final class PhoneNumber { + private final short areaCode, prefix, lineNum; + + public PhoneNumber(int areaCode, int prefix, int lineNum) { + this.areaCode = rangeCheck(areaCode, 999, "area code"); + this.prefix = rangeCheck(prefix, 999, "prefix"); + this.lineNum = rangeCheck(lineNum, 9999, "line num"); + } + + private static short rangeCheck(int val, int max, String arg) { + if (val < 0 || val > max) + throw new IllegalArgumentException(arg + ": " + val); + return (short) val; + } + + @Override public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof PhoneNumber)) + return false; + PhoneNumber pn = (PhoneNumber)o; + return pn.lineNum == lineNum && pn.prefix == prefix + && pn.areaCode == areaCode; + } + + @Override + public int hashCode() { + return Hashing.goodFastHash(32) + .hashObject(this, PhoneNumberFunnel.INSTANCE) + .hashCode(); + } + + private static class PhoneNumberFunnel implements Funnel { + + private static final PhoneNumberFunnel INSTANCE = new PhoneNumberFunnel(); + + @Override + public void funnel(PhoneNumber from, PrimitiveSink into) { + into.putShort(from.areaCode).putShort(from.prefix).putShort(from.lineNum); + } + } + +} diff --git a/src/main/java/me/whiteship/chapter02/item11/hashcode/PhoneNumber.java b/src/main/java/me/whiteship/chapter02/item11/hashcode/PhoneNumber.java new file mode 100644 index 0000000..918f8d3 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item11/hashcode/PhoneNumber.java @@ -0,0 +1,78 @@ +package me.whiteship.chapter02.item11.hashcode; + +import me.whiteship.chapter02.item10.Point; + +import java.util.*; + +// equals를 재정의하면 hashCode로 재정의해야 함을 보여준다. (70-71쪽) +public final class PhoneNumber { + private final short areaCode, prefix, lineNum; + + public PhoneNumber(int areaCode, int prefix, int lineNum) { + this.areaCode = rangeCheck(areaCode, 999, "area code"); + this.prefix = rangeCheck(prefix, 999, "prefix"); + this.lineNum = rangeCheck(lineNum, 9999, "line num"); + } + + private static short rangeCheck(int val, int max, String arg) { + if (val < 0 || val > max) + throw new IllegalArgumentException(arg + ": " + val); + return (short) val; + } + + @Override public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof PhoneNumber)) + return false; + PhoneNumber pn = (PhoneNumber)o; + return pn.lineNum == lineNum && pn.prefix == prefix + && pn.areaCode == areaCode; + } + +// @Override +// public int hashCode() { +// return 42; +// } + + // hashCode 없이는 제대로 동작하지 않는다. 다음 셋 중 하나를 활성화하자. + + // 코드 11-2 전형적인 hashCode 메서드 (70쪽) +// @Override public int hashCode() { +// int result = Short.hashCode(areaCode); // 1 +// result = 800000 * result + Short.hashCode(prefix); // 2 +// result = 800000 * result + Short.hashCode(lineNum); // 3 +// return result; +// } + + // 코드 11-3 한 줄짜리 hashCode 메서드 - 성능이 살짝 아쉽다. (71쪽) +// @Override public int hashCode() { +// return Objects.hash(lineNum, prefix, areaCode); +// } + + // 해시코드를 지연 초기화하는 hashCode 메서드 - 스레드 안정성까지 고려해야 한다. (71쪽) + private volatile int hashCode; // 자동으로 0으로 초기화된다. + + @Override public int hashCode() { + if (this.hashCode != 0) { + return hashCode; + } + + synchronized (this) { + int result = hashCode; + if (result == 0) { + result = Short.hashCode(areaCode); + result = 31 * result + Short.hashCode(prefix); + result = 31 * result + Short.hashCode(lineNum); + this.hashCode = result; + } + return result; + } + } + + public static void main(String[] args) { + Map m = new HashMap<>(); + m.put(new PhoneNumber(707, 867, 5309), "제니"); + System.out.println(m.get(new PhoneNumber(707, 867, 5309))); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item11/hashtable/HashMapTest.java b/src/main/java/me/whiteship/chapter02/item11/hashtable/HashMapTest.java new file mode 100644 index 0000000..3a6338c --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item11/hashtable/HashMapTest.java @@ -0,0 +1,28 @@ +package me.whiteship.chapter02.item11.hashtable; + +import me.whiteship.chapter02.item11.guava.PhoneNumber; + +import java.util.HashMap; +import java.util.Map; + +public class HashMapTest { + + public static void main(String[] args) { + Map map = new HashMap<>(); + + PhoneNumber number1 = new PhoneNumber(123, 456, 7890); + PhoneNumber number2 = new PhoneNumber(456, 789, 1111); + +// TODO 같은 인스턴스인데 다른 hashCode +// 다른 인스턴스인데 같은 hashCode를 쓴다면? + System.out.println(number1.equals(number2)); + System.out.println(number1.hashCode()); + System.out.println(number2.hashCode()); + + map.put(number1, "keesun"); + map.put(number2, "whiteship"); + + String s = map.get(number2); + System.out.println(s); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item11/package-info.java b/src/main/java/me/whiteship/chapter02/item11/package-info.java new file mode 100644 index 0000000..b899588 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item11/package-info.java @@ -0,0 +1 @@ +package me.whiteship.chapter02.item11; \ No newline at end of file diff --git a/src/main/java/me/whiteship/chapter02/item12/PhoneNumber.java b/src/main/java/me/whiteship/chapter02/item12/PhoneNumber.java new file mode 100644 index 0000000..c7c011f --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item12/PhoneNumber.java @@ -0,0 +1,83 @@ +package me.whiteship.chapter02.item12; + +import lombok.ToString; + +// PhoneNumber에 toString 메서드 추가 (75쪽) +public final class PhoneNumber { + private final short areaCode, prefix, lineNum; + + public PhoneNumber(int areaCode, int prefix, int lineNum) { + this.areaCode = rangeCheck(areaCode, 999, "지역코드"); + this.prefix = rangeCheck(prefix, 999, "프리픽스"); + this.lineNum = rangeCheck(lineNum, 9999, "가입자 번호"); + } + + private static short rangeCheck(int val, int max, String arg) { + if (val < 0 || val > max) + throw new IllegalArgumentException(arg + ": " + val); + return (short) val; + } + + /** + * 이 전화번호의 문자열 표현을 반환한다. + * 이 문자열은 "XXX-YYY-ZZZZ" 형태의 12글자로 구성된다. + * XXX는 지역 코드, YYY는 프리픽스, ZZZZ는 가입자 번호다. + * 각각의 대문자는 10진수 숫자 하나를 나타낸다. + * + * 전화번호의 각 부분의 값이 너무 작아서 자릿수를 채울 수 없다면, + * 앞에서부터 0으로 채워나간다. 예컨대 가입자 번호가 123이라면 + * 전화번호의 마지막 네 문자는 "0123"이 된다. + */ + @Override public String toString() { + return String.format("%03d-%03d-%04d", + areaCode, prefix, lineNum); + } + + public static PhoneNumber of(String phoneNumberString) { + String[] split = phoneNumberString.split("-"); + PhoneNumber phoneNumber = new PhoneNumber( + Short.parseShort(split[0]), + Short.parseShort(split[1]), + Short.parseShort(split[2])); + return phoneNumber; + } + + @Override public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof PhoneNumber)) + return false; + PhoneNumber pn = (PhoneNumber)o; + return pn.lineNum == lineNum && pn.prefix == prefix + && pn.areaCode == areaCode; + } + + @Override public int hashCode() { + int result = Short.hashCode(areaCode); + result = 31 * result + Short.hashCode(prefix); + result = 31 * result + Short.hashCode(lineNum); + return result; + } + + public short getAreaCode() { + return areaCode; + } + + public short getPrefix() { + return prefix; + } + + public short getLineNum() { + return lineNum; + } + + public static void main(String[] args) { + PhoneNumber jenny = new PhoneNumber(707, 867, 5309); + System.out.println("제니의 번호: " + jenny); + + PhoneNumber phoneNumber = PhoneNumber.of("707-867-5309"); + System.out.println(phoneNumber); + System.out.println(jenny.equals(phoneNumber)); + System.out.println(jenny.hashCode() == phoneNumber.hashCode()); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item13/EmptyStackException.java b/src/main/java/me/whiteship/chapter02/item13/EmptyStackException.java new file mode 100644 index 0000000..f3cea49 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/EmptyStackException.java @@ -0,0 +1,4 @@ +package me.whiteship.chapter02.item13; + +public class EmptyStackException extends IllegalStateException { +} diff --git a/src/main/java/me/whiteship/chapter02/item13/HashTable.java b/src/main/java/me/whiteship/chapter02/item13/HashTable.java new file mode 100644 index 0000000..7d07b6a --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/HashTable.java @@ -0,0 +1,87 @@ +package me.whiteship.chapter02.item13; + +public class HashTable implements Cloneable { + + private Entry[] buckets = new Entry[10]; + + private static class Entry { + final Object key; + Object value; + Entry next; + + Entry(Object key, Object value, Entry next) { + this.key = key; + this.value = value; + this.next = next; + } + + public void add(Object key, Object value) { + this.next = new Entry(key, value, null); + } + +// public Entry deepCopy() { +// return new Entry(key, value, next == null ? null : next.deepCopy()); +// } + + public Entry deepCopy() { + Entry result = new Entry(key, value, next); + for (Entry p = result ; p.next != null ; p = p.next) { + p.next = new Entry(p.next.key, p.next.value, p.next.next); + } + return result; + } + } + + /** + * TODO hasTable -> entryH[], + * TODO copy -> entryC[] + * TODO entryH[0] == entryC[0] + * + * @return + */ +// @Override +// public HashTable clone() { +// HashTable result = null; +// try { +// result = (HashTable)super.clone(); +// result.buckets = this.buckets.clone(); // p82, shallow copy 라서 위험하다. +// return result; +// } catch (CloneNotSupportedException e) { +// throw new AssertionError(); +// } +// } + + /** + * TODO hasTable -> entryH[], + * TODO copy -> entryC[] + * TODO entryH[0] != entryC[0] + * + * @return + */ + @Override + public HashTable clone() { + HashTable result = null; + try { + result = (HashTable)super.clone(); + result.buckets = new Entry[this.buckets.length]; + + for (int i = 0 ; i < this.buckets.length; i++) { + if (buckets[i] != null) { + result.buckets[i] = this.buckets[i].deepCopy(); // p83, deep copy + } + } + return result; + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } + + public static void main(String[] args) { + HashTable hashTable = new HashTable(); + Entry entry = new Entry(new Object(), new Object(), null); + hashTable.buckets[0] = entry; + HashTable clone = hashTable.clone(); + System.out.println(hashTable.buckets[0] == entry); + System.out.println(hashTable.buckets[0] == clone.buckets[0]); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item13/PhoneNumber.java b/src/main/java/me/whiteship/chapter02/item13/PhoneNumber.java new file mode 100644 index 0000000..4dbae02 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/PhoneNumber.java @@ -0,0 +1,82 @@ +package me.whiteship.chapter02.item13; + +import java.util.HashMap; +import java.util.Map; + +// PhoneNumber에 clone 메서드 추가 (79쪽) +public final class PhoneNumber implements Cloneable { + private final short areaCode, prefix, lineNum; + + public PhoneNumber(int areaCode, int prefix, int lineNum) { + this.areaCode = rangeCheck(areaCode, 999, "지역코드"); + this.prefix = rangeCheck(prefix, 999, "프리픽스"); + this.lineNum = rangeCheck(lineNum, 9999, "가입자 번호"); + System.out.println("constructor is called"); + } + + public PhoneNumber(PhoneNumber phoneNumber) { + this(phoneNumber.areaCode, phoneNumber.prefix, phoneNumber.lineNum); + } + + private static short rangeCheck(int val, int max, String arg) { + if (val < 0 || val > max) + throw new IllegalArgumentException(arg + ": " + val); + return (short) val; + } + + // 코드 13-1 가변 상태를 참조하지 않는 클래스용 clone 메서드 (79쪽) + @Override + public PhoneNumber clone() { + try { + return (PhoneNumber) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(); // 일어날 수 없는 일이다. + } + } + + public static void main(String[] args) { + PhoneNumber pn = new PhoneNumber(707, 867, 5309); + Map m = new HashMap<>(); + m.put(pn, "제니"); + PhoneNumber clone = pn.clone(); + System.out.println(m.get(clone)); + + System.out.println(clone != pn); // 반드시 true + System.out.println(clone.getClass() == pn.getClass()); // 반드시 true + System.out.println(clone.equals(pn)); // true가 아닐 수도 있다. + } + + @Override public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof PhoneNumber)) + return false; + PhoneNumber pn = (PhoneNumber)o; + return pn.lineNum == lineNum && pn.prefix == prefix + && pn.areaCode == areaCode; + } + + @Override public int hashCode() { + int result = Short.hashCode(areaCode); + result = 31 * result + Short.hashCode(prefix); + result = 31 * result + Short.hashCode(lineNum); + return result; + } + + /** + * 이 전화번호의 문자열 표현을 반환한다. + * 이 문자열은 "XXX-YYY-ZZZZ" 형태의 12글자로 구성된다. + * XXX는 지역 코드, YYY는 프리픽스, ZZZZ는 가입자 번호다. + * 각각의 대문자는 10진수 숫자 하나를 나타낸다. + * + * 전화번호의 각 부분의 값이 너무 작아서 자릿수를 채울 수 없다면, + * 앞에서부터 0으로 채워나간다. 예컨대 가입자 번호가 123이라면 + * 전화번호의 마지막 네 문자는 "0123"이 된다. + */ + @Override public String toString() { + return String.format("%03d-%03d-%04d", + areaCode, prefix, lineNum); + } + + +} diff --git a/src/main/java/me/whiteship/chapter02/item13/Stack.java b/src/main/java/me/whiteship/chapter02/item13/Stack.java new file mode 100644 index 0000000..8192cb2 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/Stack.java @@ -0,0 +1,74 @@ +package me.whiteship.chapter02.item13; +import java.util.Arrays; + +// Stack의 복제 가능 버전 (80-81쪽) +public class Stack implements Cloneable { + private Object[] elements; + private int size = 0; + private static final int DEFAULT_INITIAL_CAPACITY = 16; + + public Stack() { + this.elements = new Object[DEFAULT_INITIAL_CAPACITY]; + } + + public void push(Object e) { + ensureCapacity(); + elements[size++] = e; + } + + public Object pop() { + if (size == 0) + throw new EmptyStackException(); + Object result = elements[--size]; + elements[size] = null; // 다 쓴 참조 해제 + return result; + } + + public boolean isEmpty() { + return size ==0; + } + + // 코드 13-2 가변 상태를 참조하는 클래스용 clone 메서드 + // TODO stack -> elementsS[0, 1] + // TODO copy -> elementsC[0, 1] + // TODO elementsS[0] == elementsC[0] + + @Override public Stack clone() { + try { + Stack result = (Stack) super.clone(); + result.elements = elements.clone(); + return result; + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } + + // 원소를 위한 공간을 적어도 하나 이상 확보한다. + private void ensureCapacity() { + if (elements.length == size) + elements = Arrays.copyOf(elements, 2 * size + 1); + } + + // clone이 동작하는 모습을 보려면 명령줄 인수를 몇 개 덧붙여서 호출해야 한다. + public static void main(String[] args) { + Object[] values = new Object[2]; + values[0] = new PhoneNumber(123, 456, 7890); + values[1] = new PhoneNumber(321, 764, 2341); + + Stack stack = new Stack(); + for (Object arg : values) + stack.push(arg); + + Stack copy = stack.clone(); + + System.out.println("pop from stack"); + while (!stack.isEmpty()) + System.out.println(stack.pop() + " "); + + System.out.println("pop from copy"); + while (!copy.isEmpty()) + System.out.println(copy.pop() + " "); + + System.out.println(stack.elements[0] == copy.elements[0]); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item13/clone_use_constructor/Item.java b/src/main/java/me/whiteship/chapter02/item13/clone_use_constructor/Item.java new file mode 100644 index 0000000..41597a1 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/clone_use_constructor/Item.java @@ -0,0 +1,17 @@ +package me.whiteship.chapter02.item13.clone_use_constructor; + +public class Item implements Cloneable { + + private String name; + + /** + * 이렇게 구현하면 하위 클래스의 clone()이 깨질 수 있다. p78 + * @return + */ + @Override + public Item clone() { + Item item = new Item(); + item.name = this.name; + return item; + } +} diff --git a/src/main/java/me/whiteship/chapter02/item13/clone_use_constructor/SubItem.java b/src/main/java/me/whiteship/chapter02/item13/clone_use_constructor/SubItem.java new file mode 100644 index 0000000..b96d157 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/clone_use_constructor/SubItem.java @@ -0,0 +1,20 @@ +package me.whiteship.chapter02.item13.clone_use_constructor; + +public class SubItem extends Item implements Cloneable { + + private String name; + + @Override + public SubItem clone() { + return (SubItem)super.clone(); + } + + public static void main(String[] args) { + SubItem item = new SubItem(); + SubItem clone = item.clone(); + + System.out.println(clone != item); + System.out.println(clone.getClass() == item.getClass()); + System.out.println(clone.equals(item)); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item13/copy_constructor/HashSetExample.java b/src/main/java/me/whiteship/chapter02/item13/copy_constructor/HashSetExample.java new file mode 100644 index 0000000..f57b6c8 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/copy_constructor/HashSetExample.java @@ -0,0 +1,19 @@ +package me.whiteship.chapter02.item13.copy_constructor; + +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; + +public class HashSetExample { + + public static void main(String[] args) { + Set hashSet = new HashSet<>(); + hashSet.add("keesun"); + hashSet.add("whiteship"); + System.out.println("HashSet: " + hashSet); + + Set treeSet = new TreeSet<>(hashSet); + + System.out.println("TreeSet: " + treeSet); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item13/exception/MyApp.java b/src/main/java/me/whiteship/chapter02/item13/exception/MyApp.java new file mode 100644 index 0000000..1612ec8 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/exception/MyApp.java @@ -0,0 +1,26 @@ +package me.whiteship.chapter02.item13.exception; + +public class MyApp { + + /** + * + * @param name + * @throws MyException + */ + public void hello(String name) throws MyException { + if (name.equals("푸틴")) { + throw new MyException(); + } + + System.out.println("hello"); + } + + public static void main(String[] args) { + MyApp myApp = new MyApp(); + try { + myApp.hello("푸틴"); + } catch (MyException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/me/whiteship/chapter02/item13/exception/MyException.java b/src/main/java/me/whiteship/chapter02/item13/exception/MyException.java new file mode 100644 index 0000000..7c0ca22 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/exception/MyException.java @@ -0,0 +1,4 @@ +package me.whiteship.chapter02.item13.exception; + +public class MyException extends Exception { +} diff --git a/src/main/java/me/whiteship/chapter02/item13/inheritance/Shape.java b/src/main/java/me/whiteship/chapter02/item13/inheritance/Shape.java new file mode 100644 index 0000000..34244cc --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/inheritance/Shape.java @@ -0,0 +1,32 @@ +package me.whiteship.chapter02.item13.inheritance; + +/** + * p84, p126 일반적으로 상속용 클래스에 Cloneable 인터페이스 사용을 권장하지 않는다. + * 해당 클래스를 확장하려는 프로그래머에게 많은 부담을 주기 때문이다. + */ +public abstract class Shape implements Cloneable { + + private int area; + + public abstract int getArea(); + + + /** + * p84, 부담을 덜기 위해서는 기본 clone() 구현체를 제공하여, + * Cloenable 구현 여부를 서브 클래스가 선택할 수 있다. + * @return + * @throws CloneNotSupportedException + */ + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + /** + * p85, Cloneable 구현을 막을 수도 있다. + */ +// @Override +// protected final Object clone() throws CloneNotSupportedException { +// throw new CloneNotSupportedException(); +// } +} diff --git a/src/main/java/me/whiteship/chapter02/item13/inheritance/Square.java b/src/main/java/me/whiteship/chapter02/item13/inheritance/Square.java new file mode 100644 index 0000000..2d99e56 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/inheritance/Square.java @@ -0,0 +1,22 @@ +package me.whiteship.chapter02.item13.inheritance; + +public class Square extends Shape { + + private int length, height; + + public Square(int length, int height) { + this.length = length; + this.height = height; + } + + public static void main(String[] args) throws CloneNotSupportedException { + Square square = new Square(10, 2); + Square copy = (Square) square.clone(); + System.out.println(copy.getArea()); + } + + @Override + public int getArea() { + return this.length * this.height; + } +} diff --git a/src/main/java/me/whiteship/chapter02/item13/treeset/TreeSetExample.java b/src/main/java/me/whiteship/chapter02/item13/treeset/TreeSetExample.java new file mode 100644 index 0000000..e335637 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item13/treeset/TreeSetExample.java @@ -0,0 +1,28 @@ +package me.whiteship.chapter02.item13.treeset; + +import me.whiteship.chapter02.item13.PhoneNumber; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; + +public class TreeSetExample { + + public static void main(String[] args) { +// TreeSet numbers = new TreeSet<>(); +// numbers.add(10); +// numbers.add(4); +// numbers.add(6); + + TreeSet numbers = new TreeSet<>(Comparator.comparingInt(PhoneNumber::hashCode)); + Set phoneNumbers = Collections.synchronizedSet(numbers); + phoneNumbers.add(new PhoneNumber(123, 456, 780)); + phoneNumbers.add(new PhoneNumber(123, 456, 7890)); + phoneNumbers.add(new PhoneNumber(123, 456, 789)); + + for (PhoneNumber number : numbers) { + System.out.println(number); + } + } +} diff --git a/src/main/java/me/whiteship/chapter02/item14/CaseInsensitiveString.java b/src/main/java/me/whiteship/chapter02/item14/CaseInsensitiveString.java new file mode 100644 index 0000000..57f9335 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/CaseInsensitiveString.java @@ -0,0 +1,41 @@ +package me.whiteship.chapter02.item14; + +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; + +// 코드 14-1 객체 참조 필드가 하나뿐인 비교자 (90쪽) +public final class CaseInsensitiveString + implements Comparable { + private final String s; + + public CaseInsensitiveString(String s) { + this.s = Objects.requireNonNull(s); + } + + // 수정된 equals 메서드 (56쪽) + @Override public boolean equals(Object o) { + return o instanceof CaseInsensitiveString && + ((CaseInsensitiveString) o).s.equalsIgnoreCase(s); + } + + @Override public int hashCode() { + return s.hashCode(); + } + + @Override public String toString() { + return s; + } + + // 자바가 제공하는 비교자를 사용해 클래스를 비교한다. + public int compareTo(CaseInsensitiveString cis) { + return String.CASE_INSENSITIVE_ORDER.compare(s, cis.s); + } + + public static void main(String[] args) { + Set s = new TreeSet<>(); + for (String arg : args) + s.add(new CaseInsensitiveString(arg)); + System.out.println(s); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item14/CompareToConvention.java b/src/main/java/me/whiteship/chapter02/item14/CompareToConvention.java new file mode 100644 index 0000000..59e8765 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/CompareToConvention.java @@ -0,0 +1,36 @@ +package me.whiteship.chapter02.item14; + +import java.math.BigDecimal; + +public class CompareToConvention { + + public static void main(String[] args) { + BigDecimal n1 = BigDecimal.valueOf(23134134); + BigDecimal n2 = BigDecimal.valueOf(11231230); + BigDecimal n3 = BigDecimal.valueOf(53534552); + BigDecimal n4 = BigDecimal.valueOf(11231230); + + // p88, 반사성 + System.out.println(n1.compareTo(n1)); + + // p88, 대칭성 + System.out.println(n1.compareTo(n2)); + System.out.println(n2.compareTo(n1)); + + // p89, 추이성 + System.out.println(n3.compareTo(n1) > 0); + System.out.println(n1.compareTo(n2) > 0); + System.out.println(n3.compareTo(n2) > 0); + + // p89, 일관성 + System.out.println(n4.compareTo(n2)); + System.out.println(n2.compareTo(n1)); + System.out.println(n4.compareTo(n1)); + + // p89, compareTo가 0이라면 equals는 true여야 한다. (아닐 수도 있고..) + BigDecimal oneZero = new BigDecimal("1.0"); + BigDecimal oneZeroZero = new BigDecimal("1.00"); + System.out.println(oneZero.compareTo(oneZeroZero)); // Tree, TreeMap + System.out.println(oneZero.equals(oneZeroZero)); // 순서가 없는 콜렉션 + } +} diff --git a/src/main/java/me/whiteship/chapter02/item14/PhoneNumber.java b/src/main/java/me/whiteship/chapter02/item14/PhoneNumber.java new file mode 100644 index 0000000..b83e73b --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/PhoneNumber.java @@ -0,0 +1,107 @@ +package me.whiteship.chapter02.item14; + +import me.whiteship.chapter02.item10.Point; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; + +import static java.util.Comparator.comparingInt; + +// PhoneNumber를 비교할 수 있게 만든다. (91-92쪽) +public final class PhoneNumber implements Cloneable, Comparable { + private final short areaCode, prefix, lineNum; + + public short getAreaCode() { + return areaCode; + } + + public short getPrefix() { + return prefix; + } + + public short getLineNum() { + return lineNum; + } + + public PhoneNumber(int areaCode, int prefix, int lineNum) { + this.areaCode = rangeCheck(areaCode, 999, "지역코드"); + this.prefix = rangeCheck(prefix, 999, "프리픽스"); + this.lineNum = rangeCheck(lineNum, 9999, "가입자 번호"); + } + + private static short rangeCheck(int val, int max, String arg) { + if (val < 0 || val > max) + throw new IllegalArgumentException(arg + ": " + val); + return (short) val; + } + + @Override public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof PhoneNumber)) + return false; + PhoneNumber pn = (PhoneNumber)o; + return pn.lineNum == lineNum && pn.prefix == prefix + && pn.areaCode == areaCode; + } + + @Override public int hashCode() { + int result = Short.hashCode(areaCode); + result = 31 * result + Short.hashCode(prefix); + result = 31 * result + Short.hashCode(lineNum); + return result; + } + + /** + * 이 전화번호의 문자열 표현을 반환한다. + * 이 문자열은 "XXX-YYY-ZZZZ" 형태의 12글자로 구성된다. + * XXX는 지역 코드, YYY는 프리픽스, ZZZZ는 가입자 번호다. + * 각각의 대문자는 10진수 숫자 하나를 나타낸다. + * + * 전화번호의 각 부분의 값이 너무 작아서 자릿수를 채울 수 없다면, + * 앞에서부터 0으로 채워나간다. 예컨대 가입자 번호가 123이라면 + * 전화번호의 마지막 네 문자는 "0123"이 된다. + */ + @Override public String toString() { + return String.format("%03d-%03d-%04d", + areaCode, prefix, lineNum); + } + + // 코드 14-2 기본 타입 필드가 여럿일 때의 비교자 (91쪽) + @Override + public int compareTo(PhoneNumber pn) { + int result = Short.compare(areaCode, pn.areaCode); + if (result == 0) { + result = Short.compare(prefix, pn.prefix); + if (result == 0) + result = Short.compare(lineNum, pn.lineNum); + } + return result; + } + + // 코드 14-3 비교자 생성 메서드를 활용한 비교자 (92쪽) + private static final Comparator COMPARATOR = + comparingInt((PhoneNumber pn) -> pn.areaCode) + .thenComparingInt(pn -> pn.getPrefix()) + .thenComparingInt(pn -> pn.lineNum); +// +// @Override +// public int compareTo(PhoneNumber pn) { +// return COMPARATOR.compare(this, pn); +// } + + private static PhoneNumber randomPhoneNumber() { + Random rnd = ThreadLocalRandom.current(); + return new PhoneNumber((short) rnd.nextInt(1000), + (short) rnd.nextInt(1000), + (short) rnd.nextInt(10000)); + } + + public static void main(String[] args) { + Set s = new TreeSet<>(); + for (int i = 0; i < 10; i++) + s.add(randomPhoneNumber()); + System.out.println(s); + } + +} diff --git a/src/main/java/me/whiteship/chapter02/item14/WordList.java b/src/main/java/me/whiteship/chapter02/item14/WordList.java new file mode 100644 index 0000000..222a971 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/WordList.java @@ -0,0 +1,16 @@ +package me.whiteship.chapter02.item14; + +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; + +// Comparable 구현 시의 이점 (87쪽) +public class WordList { + public static void main(String[] args) { + String[] values = new String[]{"keesun", "whiteship", "java"}; + + Set s = new TreeSet<>(); + Collections.addAll(s, values); + System.out.println(s); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item14/composition/NamedPoint.java b/src/main/java/me/whiteship/chapter02/item14/composition/NamedPoint.java new file mode 100644 index 0000000..a5b3ef7 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/composition/NamedPoint.java @@ -0,0 +1,25 @@ +package me.whiteship.chapter02.item14.composition; + +public class NamedPoint implements Comparable { + + private final Point point; + private final String name; + + public NamedPoint(Point point, String name) { + this.point = point; + this.name = name; + } + + public Point getPoint() { + return this.point; + } + + @Override + public int compareTo(NamedPoint namedPoint) { + int result = this.point.compareTo(namedPoint.point); + if (result == 0) { + result = this.name.compareTo(namedPoint.name); + } + return result; + } +} diff --git a/src/main/java/me/whiteship/chapter02/item14/composition/Point.java b/src/main/java/me/whiteship/chapter02/item14/composition/Point.java new file mode 100644 index 0000000..6a76365 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/composition/Point.java @@ -0,0 +1,20 @@ +package me.whiteship.chapter02.item14.composition; + +public class Point implements Comparable{ + + final int x, y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public int compareTo(Point point) { + int result = Integer.compare(this.x, point.x); + if (result == 0) { + result = Integer.compare(this.y, point.y); + } + return result; + } +} diff --git a/src/main/java/me/whiteship/chapter02/item14/decimal/DecimalIsNotCorrect.java b/src/main/java/me/whiteship/chapter02/item14/decimal/DecimalIsNotCorrect.java new file mode 100644 index 0000000..4597276 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/decimal/DecimalIsNotCorrect.java @@ -0,0 +1,15 @@ +package me.whiteship.chapter02.item14.decimal; + +import java.math.BigDecimal; + +public class DecimalIsNotCorrect { + + public static void main(String[] args) { + int i = 1; + double d = 0.1; + System.out.println(i - d * 9); + + BigDecimal bd = BigDecimal.valueOf(0.1); + System.out.println(BigDecimal.valueOf(1).min(bd.multiply(BigDecimal.valueOf(9)))); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item14/decimal/IntOverflow.java b/src/main/java/me/whiteship/chapter02/item14/decimal/IntOverflow.java new file mode 100644 index 0000000..2a1c0ed --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/decimal/IntOverflow.java @@ -0,0 +1,9 @@ +package me.whiteship.chapter02.item14.decimal; + +public class IntOverflow { + + public static void main(String[] args) { + System.out.println(-2147483648 - 10); + System.out.println(Integer.compare(-2147483648, 10)); + } +} diff --git a/src/main/java/me/whiteship/chapter02/item14/interitance/NamedPoint.java b/src/main/java/me/whiteship/chapter02/item14/interitance/NamedPoint.java new file mode 100644 index 0000000..b062903 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/interitance/NamedPoint.java @@ -0,0 +1,49 @@ +package me.whiteship.chapter02.item14.interitance; + +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; + +public class NamedPoint extends Point { + + final private String name; + + public NamedPoint(int x, int y, String name) { + super(x, y); + this.name = name; + } + + @Override + public String toString() { + return "NamedPoint{" + + "name='" + name + '\'' + + ", x=" + x + + ", y=" + y + + '}'; + } + + public static void main(String[] args) { + NamedPoint p1 = new NamedPoint(1, 0, "keesun"); + NamedPoint p2 = new NamedPoint(1, 0, "whiteship"); + + Set points = new TreeSet<>(new Comparator() { + @Override + public int compare(NamedPoint p1, NamedPoint p2) { + int result = Integer.compare(p1.getX(), p2.getX()); + if (result == 0) { + result = Integer.compare(p1.getY(), p2.getY()); + } + if (result == 0) { + result = p1.name.compareTo(p2.name); + } + return result; + } + }); + + points.add(p1); + points.add(p2); + + System.out.println(points); + } + +} diff --git a/src/main/java/me/whiteship/chapter02/item14/interitance/Point.java b/src/main/java/me/whiteship/chapter02/item14/interitance/Point.java new file mode 100644 index 0000000..1839ea8 --- /dev/null +++ b/src/main/java/me/whiteship/chapter02/item14/interitance/Point.java @@ -0,0 +1,28 @@ +package me.whiteship.chapter02.item14.interitance; + +public class Point implements Comparable{ + + final int x, y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + @Override + public int compareTo(Point point) { + int result = Integer.compare(this.x, point.x); + if (result == 0) { + result = Integer.compare(this.y, point.y); + } + return result; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/src/test/java/me/whiteship/chapter01/item03/field/ConcertTest.java b/src/test/java/me/whiteship/chapter01/item03/field/ConcertTest.java new file mode 100644 index 0000000..f54cdad --- /dev/null +++ b/src/test/java/me/whiteship/chapter01/item03/field/ConcertTest.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter01.item03.field; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ConcertTest { + + @Test + void perform() { + Concert concert = new Concert(new MockElvis()); + concert.perform(); + + assertTrue(concert.isLightsOn()); + assertTrue(concert.isMainStateOpen()); + } + +} \ No newline at end of file diff --git a/src/test/java/me/whiteship/chapter01/item03/field/MockElvis.java b/src/test/java/me/whiteship/chapter01/item03/field/MockElvis.java new file mode 100644 index 0000000..ab34246 --- /dev/null +++ b/src/test/java/me/whiteship/chapter01/item03/field/MockElvis.java @@ -0,0 +1,13 @@ +package me.whiteship.chapter01.item03.field; + +public class MockElvis implements IElvis { + @Override + public void leaveTheBuilding() { + + } + + @Override + public void sing() { + System.out.println("You ain't nothin' but a hound dog."); + } +} diff --git a/src/test/java/me/whiteship/chapter01/item05/dependencyinjection/SpellCheckerTest.java b/src/test/java/me/whiteship/chapter01/item05/dependencyinjection/SpellCheckerTest.java new file mode 100644 index 0000000..dc7459c --- /dev/null +++ b/src/test/java/me/whiteship/chapter01/item05/dependencyinjection/SpellCheckerTest.java @@ -0,0 +1,14 @@ +package me.whiteship.chapter01.item05.dependencyinjection; + +import me.whiteship.chapter01.item05.MockDictionary; +import org.junit.jupiter.api.Test; + +class SpellCheckerTest { + + @Test + void isValid() { + SpellChecker spellChecker = new SpellChecker(MockDictionary::new); + spellChecker.isValid("test"); + } + +} \ No newline at end of file diff --git a/src/test/java/me/whiteship/chapter01/item05/staticutils/SpellCheckerTest.java b/src/test/java/me/whiteship/chapter01/item05/staticutils/SpellCheckerTest.java new file mode 100644 index 0000000..d32f6a2 --- /dev/null +++ b/src/test/java/me/whiteship/chapter01/item05/staticutils/SpellCheckerTest.java @@ -0,0 +1,14 @@ +package me.whiteship.chapter01.item05.staticutils; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class SpellCheckerTest { + + @Test + void isValid() { + assertTrue(SpellChecker.isValid("test")); + } + +} \ No newline at end of file diff --git a/src/test/java/me/whiteship/chapter01/item07/cache/PostRepositoryTest.java b/src/test/java/me/whiteship/chapter01/item07/cache/PostRepositoryTest.java new file mode 100644 index 0000000..5b531d5 --- /dev/null +++ b/src/test/java/me/whiteship/chapter01/item07/cache/PostRepositoryTest.java @@ -0,0 +1,61 @@ +package me.whiteship.chapter01.item07.cache; + +import org.junit.jupiter.api.Test; + +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PostRepositoryTest { + + @Test + void cache() throws InterruptedException { + PostRepository postRepository = new PostRepository(); + CacheKey key1 = new CacheKey(1); + postRepository.getPostById(key1); + + assertFalse(postRepository.getCache().isEmpty()); + + key1 = null; + // TODO run gc + System.out.println("run gc"); + System.gc(); + System.out.println("wait"); + Thread.sleep(3000L); + + assertTrue(postRepository.getCache().isEmpty()); + } + +// @Test +// void backgroundThread() throws InterruptedException { +// ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); +// PostRepository postRepository = new PostRepository(); +// CacheKey key1 = new CacheKey(1); +// postRepository.getPostById(key1); +// +// Runnable removeOldCache = () -> { +// System.out.println("running removeOldCache task"); +// Map cache = postRepository.getCache(); +// Set cacheKeys = cache.keySet(); +// Optional key = cacheKeys.stream().min(Comparator.comparing(CacheKey::getCreated)); +// key.ifPresent((k) -> { +// System.out.println("removing " + k); +// cache.remove(k); +// }); +// }; +// +// System.out.println("The time is : " + new Date()); +// +// executor.scheduleAtFixedRate(removeOldCache, +// 1, 3, TimeUnit.SECONDS); +// +// Thread.sleep(20000L); +// +// executor.shutdown(); +// } + +} \ No newline at end of file diff --git a/src/test/java/me/whiteship/chapter01/item07/listener/ChatRoomTest.java b/src/test/java/me/whiteship/chapter01/item07/listener/ChatRoomTest.java new file mode 100644 index 0000000..4ca3b82 --- /dev/null +++ b/src/test/java/me/whiteship/chapter01/item07/listener/ChatRoomTest.java @@ -0,0 +1,33 @@ +package me.whiteship.chapter01.item07.listener; + +import org.junit.jupiter.api.Test; + +import java.lang.ref.WeakReference; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class ChatRoomTest { + + @Test + void charRoom() throws InterruptedException { + ChatRoom chatRoom = new ChatRoom(); + User user1 = new User(); + User user2 = new User(); + + chatRoom.addUser(user1); + chatRoom.addUser(user2); + + chatRoom.sendMessage("hello"); + + user1 = null; + + System.gc(); + + Thread.sleep(5000L); + + List> users = chatRoom.getUsers(); + assertTrue(users.size() == 1); + } + +} \ No newline at end of file diff --git a/src/test/java/me/whiteship/chapter01/item07/optional/ChannelTest.java b/src/test/java/me/whiteship/chapter01/item07/optional/ChannelTest.java new file mode 100644 index 0000000..5787aa2 --- /dev/null +++ b/src/test/java/me/whiteship/chapter01/item07/optional/ChannelTest.java @@ -0,0 +1,18 @@ +package me.whiteship.chapter01.item07.optional; + +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +class ChannelTest { + + @Test + void npe() { + Channel channel = new Channel(); + Optional optional = channel.defaultMemberShip(); + optional.ifPresent(MemberShip::hello); + } + +} \ No newline at end of file diff --git a/src/test/java/me/whiteship/chapter01/item08/finalizer_attack/AccountTest.java b/src/test/java/me/whiteship/chapter01/item08/finalizer_attack/AccountTest.java new file mode 100644 index 0000000..3d1ea8b --- /dev/null +++ b/src/test/java/me/whiteship/chapter01/item08/finalizer_attack/AccountTest.java @@ -0,0 +1,28 @@ +package me.whiteship.chapter01.item08.finalizer_attack; + +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +class AccountTest { + + @Test + void 일반_계정() { + Account account = new Account("keesun"); + account.transfer(BigDecimal.valueOf(10.4),"hello"); + } + + @Test + void 푸틴_계정() throws InterruptedException { + Account account = null; + try { + account = new BrokenAccount("푸틴"); + } catch (Exception exception) { + System.out.println("이러면???"); + } + + System.gc(); + Thread.sleep(3000L); + } + +} \ No newline at end of file From 7d14f089526868cfe606a95d4315107eae772042 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Jun 2022 11:41:14 +0900 Subject: [PATCH 2/8] success --- pom.xml | 19 ++++++++++++++----- .../whiteship/chapter01/item01/AppConfig.java | 12 ++++++------ .../chapter01/item01/HelloServiceFactory.java | 6 +++--- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/pom.xml b/pom.xml index 855b8f9..a5b1c70 100644 --- a/pom.xml +++ b/pom.xml @@ -34,11 +34,11 @@ 1.9 - - me.whiteship.hello - chinese-hello-service - 0.0.1-SNAPSHOT - + + + + + org.springframework.boot @@ -57,4 +57,13 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + + diff --git a/src/main/java/me/whiteship/chapter01/item01/AppConfig.java b/src/main/java/me/whiteship/chapter01/item01/AppConfig.java index 3634694..b7cff42 100644 --- a/src/main/java/me/whiteship/chapter01/item01/AppConfig.java +++ b/src/main/java/me/whiteship/chapter01/item01/AppConfig.java @@ -1,15 +1,15 @@ package me.whiteship.chapter01.item01; -import me.whiteship.hello.ChineseHelloService; +//import me.whiteship.hello.ChineseHelloService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { - - @Bean - public HelloService helloService() { - return new ChineseHelloService(); - } +// +// @Bean +// public HelloService helloService() { +// return new ChineseHelloService(); +// } } diff --git a/src/main/java/me/whiteship/chapter01/item01/HelloServiceFactory.java b/src/main/java/me/whiteship/chapter01/item01/HelloServiceFactory.java index 04cadc2..a552e61 100644 --- a/src/main/java/me/whiteship/chapter01/item01/HelloServiceFactory.java +++ b/src/main/java/me/whiteship/chapter01/item01/HelloServiceFactory.java @@ -1,6 +1,6 @@ package me.whiteship.chapter01.item01; -import me.whiteship.hello.ChineseHelloService; +//import me.whiteship.hello.ChineseHelloService; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -16,8 +16,8 @@ public static void main(String[] args) throws ClassNotFoundException, NoSuchMeth System.out.println(h.hello()); }); - HelloService helloService = new ChineseHelloService(); - System.out.println(helloService.hello()); +// HelloService helloService = new ChineseHelloService(); +// System.out.println(helloService.hello()); // Class aClass = Class.forName("me.whiteship.hello.ChineseHelloService"); // Constructor constructor = aClass.getConstructor(); From 61cc066336ad1c2dfe83ae6272accc85ea36258b Mon Sep 17 00:00:00 2001 From: HEEJIN JEON Date: Tue, 7 Jun 2022 12:06:41 +0900 Subject: [PATCH 3/8] Delete .gitignore --- .gitignore | 265 ----------------------------------------------------- 1 file changed, 265 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 30cd846..0000000 --- a/.gitignore +++ /dev/null @@ -1,265 +0,0 @@ - -# Created by https://www.toptal.com/developers/gitignore/api/windows,macos,intellij,eclipse,java -# Edit at https://www.toptal.com/developers/gitignore?templates=windows,macos,intellij,eclipse,java - -### Eclipse ### -.metadata -bin/ -tmp/ -*.tmp -*.bak -*.swp -*~.nib -local.properties -.settings/ -.loadpath -.recommenders - -# External tool builders -.externalToolBuilders/ - -# Locally stored "Eclipse launch configurations" -*.launch - -# PyDev specific (Python IDE for Eclipse) -*.pydevproject - -# CDT-specific (C/C++ Development Tooling) -.cproject - -# CDT- autotools -.autotools - -# Java annotation processor (APT) -.factorypath - -# PDT-specific (PHP Development Tools) -.buildpath - -# sbteclipse plugin -.target - -# Tern plugin -.tern-project - -# TeXlipse plugin -.texlipse - -# STS (Spring Tool Suite) -.springBeans - -# Code Recommenders -.recommenders/ - -# Annotation Processing -.apt_generated/ -.apt_generated_test/ - -# Scala IDE specific (Scala & Java development for Eclipse) -.cache-main -.scala_dependencies -.worksheet - -# Uncomment this line if you wish to ignore the project description file. -# Typically, this file would be tracked if it contains build/dependency configurations: -#.project - -### Eclipse Patch ### -# Spring Boot Tooling -.sts4-cache/ - -### Intellij ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# SonarLint plugin -.idea/sonarlint/ - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### Intellij Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -# https://plugins.jetbrains.com/plugin/7973-sonarlint -.idea/**/sonarlint/ - -# SonarQube Plugin -# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin -.idea/**/sonarIssues.xml - -# Markdown Navigator plugin -# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced -.idea/**/markdown-navigator.xml -.idea/**/markdown-navigator-enh.xml -.idea/**/markdown-navigator/ - -# Cache file creation bug -# See https://youtrack.jetbrains.com/issue/JBR-2257 -.idea/$CACHE_FILE$ - -# CodeStream plugin -# https://plugins.jetbrains.com/plugin/12206-codestream -.idea/codestream.xml - -### Java ### -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -replay_pid* - -### macOS ### -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### macOS Patch ### -# iCloud generated files -*.icloud - -### Windows ### -# Windows thumbnail cache files -Thumbs.db -Thumbs.db:encryptable -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk - -# End of https://www.toptal.com/developers/gitignore/api/windows,macos,intellij,eclipse,java \ No newline at end of file From 4cb5262f60c66aab414b475662b0f0cf36ef8ccd Mon Sep 17 00:00:00 2001 From: HEEJIN JEON Date: Tue, 7 Jun 2022 12:06:49 +0900 Subject: [PATCH 4/8] Delete README.md --- README.md | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index ed389c0..0000000 --- a/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# 이펙티브 자바 스터디 - -> 2022\. 05. 28 ~ - -
- -## 스터디원 - -[김재호](https://github.com/chamominedev) [이민지](https://github.com/MinJee-lee) [임대진](https://github.com/fineapplepizza) [전선규](https://github.com/sungyujeon) [전희진](https://github.com/h2jinee) - -
- -## 학습내용 - -1장 들어가기 - -2장 객체 생성과 파괴 - -|아이템|내용|발표자|참고링크| -|:-:|:---:|:---:|:---:| -|1|생성자 대신 정적 팩터리 메서드를 고려하라|전희진|| -|2|생성자에 매개변수가 많다면 빌더를 고려하라|김재호|| -|3|private 생성자나 열거 타입으로 싱글턴임을 보증하라|전선규|| -|4|인스턴스화를 막으려거든 private 생성자를 사용하라|이민지|| -|5|자원을 직접 명시하지 말고 의존 객체 주입을 사용하라|임대진|| - From 252c86091dba0859c78c23f531830bc89d918804 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Jun 2022 12:11:59 +0900 Subject: [PATCH 5/8] success --- effective-java.git/HEAD | 1 + effective-java.git/config | 10 + effective-java.git/description | 1 + .../hooks/applypatch-msg.sample | 15 ++ effective-java.git/hooks/commit-msg.sample | 24 +++ .../hooks/fsmonitor-watchman.sample | 173 ++++++++++++++++++ effective-java.git/hooks/post-update.sample | 8 + .../hooks/pre-applypatch.sample | 14 ++ effective-java.git/hooks/pre-commit.sample | 49 +++++ .../hooks/pre-merge-commit.sample | 13 ++ effective-java.git/hooks/pre-push.sample | 53 ++++++ effective-java.git/hooks/pre-rebase.sample | 169 +++++++++++++++++ effective-java.git/hooks/pre-receive.sample | 24 +++ .../hooks/prepare-commit-msg.sample | 42 +++++ .../hooks/push-to-checkout.sample | 78 ++++++++ effective-java.git/hooks/update.sample | 128 +++++++++++++ effective-java.git/info/exclude | 6 + ...45e6fb3b48ee1346b65d61b1d9bafc795fd097.idx | Bin 0 -> 6532 bytes ...5e6fb3b48ee1346b65d61b1d9bafc795fd097.pack | Bin 0 -> 91186 bytes effective-java.git/packed-refs | 7 + 20 files changed, 815 insertions(+) create mode 100644 effective-java.git/HEAD create mode 100644 effective-java.git/config create mode 100644 effective-java.git/description create mode 100644 effective-java.git/hooks/applypatch-msg.sample create mode 100644 effective-java.git/hooks/commit-msg.sample create mode 100644 effective-java.git/hooks/fsmonitor-watchman.sample create mode 100644 effective-java.git/hooks/post-update.sample create mode 100644 effective-java.git/hooks/pre-applypatch.sample create mode 100644 effective-java.git/hooks/pre-commit.sample create mode 100644 effective-java.git/hooks/pre-merge-commit.sample create mode 100644 effective-java.git/hooks/pre-push.sample create mode 100644 effective-java.git/hooks/pre-rebase.sample create mode 100644 effective-java.git/hooks/pre-receive.sample create mode 100644 effective-java.git/hooks/prepare-commit-msg.sample create mode 100644 effective-java.git/hooks/push-to-checkout.sample create mode 100644 effective-java.git/hooks/update.sample create mode 100644 effective-java.git/info/exclude create mode 100644 effective-java.git/objects/pack/pack-df45e6fb3b48ee1346b65d61b1d9bafc795fd097.idx create mode 100644 effective-java.git/objects/pack/pack-df45e6fb3b48ee1346b65d61b1d9bafc795fd097.pack create mode 100644 effective-java.git/packed-refs diff --git a/effective-java.git/HEAD b/effective-java.git/HEAD new file mode 100644 index 0000000..b870d82 --- /dev/null +++ b/effective-java.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/effective-java.git/config b/effective-java.git/config new file mode 100644 index 0000000..afffd3a --- /dev/null +++ b/effective-java.git/config @@ -0,0 +1,10 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = true + symlinks = false + ignorecase = true +[remote "origin"] + url = https://github.com/h2jinee/effective-java/ + fetch = +refs/*:refs/* + mirror = true diff --git a/effective-java.git/description b/effective-java.git/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/effective-java.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/effective-java.git/hooks/applypatch-msg.sample b/effective-java.git/hooks/applypatch-msg.sample new file mode 100644 index 0000000..a5d7b84 --- /dev/null +++ b/effective-java.git/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/effective-java.git/hooks/commit-msg.sample b/effective-java.git/hooks/commit-msg.sample new file mode 100644 index 0000000..b58d118 --- /dev/null +++ b/effective-java.git/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/effective-java.git/hooks/fsmonitor-watchman.sample b/effective-java.git/hooks/fsmonitor-watchman.sample new file mode 100644 index 0000000..14ed0aa --- /dev/null +++ b/effective-java.git/hooks/fsmonitor-watchman.sample @@ -0,0 +1,173 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 2) and last update token +# formatted as a string and outputs to stdout a new update token and +# all files that have been modified since the update token. Paths must +# be relative to the root of the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $last_update_token) = @ARGV; + +# Uncomment for debugging +# print STDERR "$0 $version $last_update_token\n"; + +# Check the hook interface version +if ($version ne 2) { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree = get_working_dir(); + +my $retry = 1; + +my $json_pkg; +eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; +} or do { + require JSON::PP; + $json_pkg = "JSON::PP"; +}; + +launch_watchman(); + +sub launch_watchman { + my $o = watchman_query(); + if (is_work_tree_watched($o)) { + output_result($o->{clock}, @{$o->{files}}); + } +} + +sub output_result { + my ($clockid, @files) = @_; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # binmode $fh, ":utf8"; + # print $fh "$clockid\n@files\n"; + # close $fh; + + binmode STDOUT, ":utf8"; + print $clockid; + print "\0"; + local $, = "\0"; + print @files; +} + +sub watchman_clock { + my $response = qx/watchman clock "$git_work_tree"/; + die "Failed to get clock id on '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + return $json_pkg->new->utf8->decode($response); +} + +sub watchman_query { + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $last_update_token but not from the .git folder. + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + if (substr($last_update_token, 0, 1) eq "c") { + $last_update_token = "\"$last_update_token\""; + } + my $query = <<" END"; + ["query", "$git_work_tree", { + "since": $last_update_token, + "fields": ["name"], + "expression": ["not", ["dirname", ".git"]] + }] + END + + # Uncomment for debugging the watchman query + # open (my $fh, ">", ".git/watchman-query.json"); + # print $fh $query; + # close $fh; + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + # Uncomment for debugging the watch response + # open ($fh, ">", ".git/watchman-response.json"); + # print $fh $response; + # close $fh; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + return $json_pkg->new->utf8->decode($response); +} + +sub is_work_tree_watched { + my ($output) = @_; + my $error = $output->{error}; + if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { + $retry--; + my $response = qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + $output = $json_pkg->new->utf8->decode($response); + $error = $output->{error}; + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # close $fh; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + my $o = watchman_clock(); + $error = $output->{error}; + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + output_result($o->{clock}, ("/")); + $last_update_token = $o->{clock}; + + eval { launch_watchman() }; + return 0; + } + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + return 1; +} + +sub get_working_dir { + my $working_dir; + if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $working_dir = Win32::GetCwd(); + $working_dir =~ tr/\\/\//; + } else { + require Cwd; + $working_dir = Cwd::cwd(); + } + + return $working_dir; +} diff --git a/effective-java.git/hooks/post-update.sample b/effective-java.git/hooks/post-update.sample new file mode 100644 index 0000000..ec17ec1 --- /dev/null +++ b/effective-java.git/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/effective-java.git/hooks/pre-applypatch.sample b/effective-java.git/hooks/pre-applypatch.sample new file mode 100644 index 0000000..4142082 --- /dev/null +++ b/effective-java.git/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/effective-java.git/hooks/pre-commit.sample b/effective-java.git/hooks/pre-commit.sample new file mode 100644 index 0000000..e144712 --- /dev/null +++ b/effective-java.git/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/effective-java.git/hooks/pre-merge-commit.sample b/effective-java.git/hooks/pre-merge-commit.sample new file mode 100644 index 0000000..399eab1 --- /dev/null +++ b/effective-java.git/hooks/pre-merge-commit.sample @@ -0,0 +1,13 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git merge" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message to +# stderr if it wants to stop the merge commit. +# +# To enable this hook, rename this file to "pre-merge-commit". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" +: diff --git a/effective-java.git/hooks/pre-push.sample b/effective-java.git/hooks/pre-push.sample new file mode 100644 index 0000000..4ce688d --- /dev/null +++ b/effective-java.git/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +zero=$(git hash-object --stdin &2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/effective-java.git/hooks/pre-rebase.sample b/effective-java.git/hooks/pre-rebase.sample new file mode 100644 index 0000000..6cbef5c --- /dev/null +++ b/effective-java.git/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/effective-java.git/hooks/pre-receive.sample b/effective-java.git/hooks/pre-receive.sample new file mode 100644 index 0000000..a1fd29e --- /dev/null +++ b/effective-java.git/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/effective-java.git/hooks/prepare-commit-msg.sample b/effective-java.git/hooks/prepare-commit-msg.sample new file mode 100644 index 0000000..10fa14c --- /dev/null +++ b/effective-java.git/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/effective-java.git/hooks/push-to-checkout.sample b/effective-java.git/hooks/push-to-checkout.sample new file mode 100644 index 0000000..af5a0c0 --- /dev/null +++ b/effective-java.git/hooks/push-to-checkout.sample @@ -0,0 +1,78 @@ +#!/bin/sh + +# An example hook script to update a checked-out tree on a git push. +# +# This hook is invoked by git-receive-pack(1) when it reacts to git +# push and updates reference(s) in its repository, and when the push +# tries to update the branch that is currently checked out and the +# receive.denyCurrentBranch configuration variable is set to +# updateInstead. +# +# By default, such a push is refused if the working tree and the index +# of the remote repository has any difference from the currently +# checked out commit; when both the working tree and the index match +# the current commit, they are updated to match the newly pushed tip +# of the branch. This hook is to be used to override the default +# behaviour; however the code below reimplements the default behaviour +# as a starting point for convenient modification. +# +# The hook receives the commit with which the tip of the current +# branch is going to be updated: +commit=$1 + +# It can exit with a non-zero status to refuse the push (when it does +# so, it must not modify the index or the working tree). +die () { + echo >&2 "$*" + exit 1 +} + +# Or it can make any necessary changes to the working tree and to the +# index to bring them to the desired state when the tip of the current +# branch is updated to the new commit, and exit with a zero status. +# +# For example, the hook can simply run git read-tree -u -m HEAD "$1" +# in order to emulate git fetch that is run in the reverse direction +# with git push, as the two-tree form of git read-tree -u -m is +# essentially the same as git switch or git checkout that switches +# branches while keeping the local changes in the working tree that do +# not interfere with the difference between the branches. + +# The below is a more-or-less exact translation to shell of the C code +# for the default behaviour for git's push-to-checkout hook defined in +# the push_to_deploy() function in builtin/receive-pack.c. +# +# Note that the hook will be executed from the repository directory, +# not from the working tree, so if you want to perform operations on +# the working tree, you will have to adapt your code accordingly, e.g. +# by adding "cd .." or using relative paths. + +if ! git update-index -q --ignore-submodules --refresh +then + die "Up-to-date check failed" +fi + +if ! git diff-files --quiet --ignore-submodules -- +then + die "Working directory has unstaged changes" +fi + +# This is a rough translation of: +# +# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX +if git cat-file -e HEAD 2>/dev/null +then + head=HEAD +else + head=$(git hash-object -t tree --stdin &2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --type=bool hooks.allowunannotated) +allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) +denycreatebranch=$(git config --type=bool hooks.denycreatebranch) +allowdeletetag=$(git config --type=bool hooks.allowdeletetag) +allowmodifytag=$(git config --type=bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero=$(git hash-object --stdin &2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/effective-java.git/info/exclude b/effective-java.git/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/effective-java.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/effective-java.git/objects/pack/pack-df45e6fb3b48ee1346b65d61b1d9bafc795fd097.idx b/effective-java.git/objects/pack/pack-df45e6fb3b48ee1346b65d61b1d9bafc795fd097.idx new file mode 100644 index 0000000000000000000000000000000000000000..73c3a1cb22a61d14efb7f5a3dd5305c51877d8d1 GIT binary patch literal 6532 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 R6;y+~^DM5(Z}*Y<{{S2qBb@*M literal 0 HcmV?d00001 diff --git a/effective-java.git/objects/pack/pack-df45e6fb3b48ee1346b65d61b1d9bafc795fd097.pack b/effective-java.git/objects/pack/pack-df45e6fb3b48ee1346b65d61b1d9bafc795fd097.pack new file mode 100644 index 0000000000000000000000000000000000000000..3034049d825ab4df237f6ae713bad3161f2a79f4 GIT binary patch literal 91186 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≧4+}QYgz&@kL#v4YI3^zh>3c- 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

@=b(g}6 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 literal 0 HcmV?d00001 diff --git a/effective-java.git/packed-refs b/effective-java.git/packed-refs new file mode 100644 index 0000000..9bd8a51 --- /dev/null +++ b/effective-java.git/packed-refs @@ -0,0 +1,7 @@ +# pack-refs with: peeled fully-peeled sorted +af592dd06cd89193d952ab8d852fb07082ea77c2 refs/heads/daejin +af592dd06cd89193d952ab8d852fb07082ea77c2 refs/heads/heejin +af592dd06cd89193d952ab8d852fb07082ea77c2 refs/heads/jaeho +a5ee82bb39eb806b0129e0fc0f4103f2aeed3949 refs/heads/main +af592dd06cd89193d952ab8d852fb07082ea77c2 refs/heads/minjee +85e1ec02f7daa6772ce41d08f55d9f253e5e9ab7 refs/heads/sungyu From 830bd113aa03afa7834a1ff297c2f0c22b24e5e3 Mon Sep 17 00:00:00 2001 From: HEEJIN JEON Date: Tue, 7 Jun 2022 13:23:06 +0900 Subject: [PATCH 6/8] Update .gitignore success --- .gitignore | 289 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 260 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index 549e00a..7e77568 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,264 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath +# Created by https://www.toptal.com/developers/gitignore/api/windows,macos,intellij,eclipse,java +# Edit at https://www.toptal.com/developers/gitignore?templates=windows,macos,intellij,eclipse,java + +### Eclipse ### +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) .factorypath -.project -.settings + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) .springBeans -.sts4-cache -### IntelliJ IDEA ### -.idea +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project + +### Eclipse Patch ### +# Spring Boot Tooling +.sts4-cache/ + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format *.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/windows,macos,intellij,eclipse,java From fba361cc55ae9853184846c2f1d2c24fd719a5dc Mon Sep 17 00:00:00 2001 From: HEEJIN JEON Date: Tue, 7 Jun 2022 13:23:33 +0900 Subject: [PATCH 7/8] Create README.md --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..382b58f --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# effective-java From e1f696f215430acc5274d041f1b9d1a0816d4a2b Mon Sep 17 00:00:00 2001 From: HEEJIN JEON Date: Tue, 7 Jun 2022 13:24:10 +0900 Subject: [PATCH 8/8] Update README.md --- README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 382b58f..0a59067 100644 --- a/README.md +++ b/README.md @@ -1 +1,26 @@ -# effective-java +# 이펙티브 자바 스터디 + +> 2022\. 05. 28 ~ + +
+ +## 스터디원 + +[김재호](https://github.com/chamominedev) [이민지](https://github.com/MinJee-lee) [임대진](https://github.com/fineapplepizza) [전선규](https://github.com/sungyujeon) [전희진](https://github.com/h2jinee) + +
+ +## 학습내용 + +1장 들어가기 + +2장 객체 생성과 파괴 + +|아이템|내용|발표자|참고링크| +|:-:|:---:|:---:|:---:| +|1|생성자 대신 정적 팩터리 메서드를 고려하라|전희진|[LINK](https://h2jinee.notion.site/1-6657e62fab5948febb2fba00c3c53046)| +|2|생성자에 매개변수가 많다면 빌더를 고려하라|김재호|[LINK](https://velog.io/@chamominedev/생성자에-매개변수가-많다면-빌더를-고려하라)| +|3|private 생성자나 열거 타입으로 싱글턴임을 보증하라|전선규|[LINK](https://github.com/sungyujeon/TIL/blob/master/java/effective-java/01_creating-destroying-objects.md)| +|4|인스턴스화를 막으려거든 private 생성자를 사용하라|이민지|| +|5|자원을 직접 명시하지 말고 의존 객체 주입을 사용하라|임대진|| +