-
Notifications
You must be signed in to change notification settings - Fork 4
create examples Kotlin Data classes features #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
3bb91cc
create examples Kotlin Data classes features
KonstantinKhan 2170a23
change position properties to 'val'
KonstantinKhan 14eec50
update according to the review comments
KonstantinKhan 287ebdf
replace assert methods
KonstantinKhan 45ed0ee
format
KonstantinKhan e017a63
refactor: update the comment
e5LA 430efae
Merge branch 'main' into demonstrate-data-classes
e5LA File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
141 changes: 141 additions & 0 deletions
141
src/main/kotlin/codecollection/kotlinfeatures/DataClass.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| // Data classes can't be abstract, open, sealed, or inner. | ||
| // The primary constructor must have at least one parameter. | ||
|
|
||
| package codecollection.kotlinfeatures | ||
|
|
||
| data class Person( | ||
| val firstName: String, | ||
| val age: Int, | ||
| val email: String, | ||
| ) | ||
|
|
||
| // Attention! Using 'var' is not recommended in the data classes. See the example. | ||
| data class MutablePerson( | ||
| var firstName: String, | ||
| var age: Int, | ||
| var email: String, | ||
| ) | ||
|
|
||
| data class Address( | ||
| var city: String, | ||
| var street: String, | ||
| ) | ||
|
|
||
| data class Employee( | ||
| val position: String = "Intern", // default property | ||
| val person: Person, | ||
| val address: Address, | ||
| ) | ||
|
|
||
| fun main() { | ||
| println("=== BASIC DATA CLASS FEATURES ===") | ||
|
|
||
| // Create instances | ||
| val person1 = Person(firstName = "Alice", age = 30, email = "[email protected]") | ||
| val person2 = Person(firstName = "Bob", age = 32, email = "[email protected]") | ||
| val person3 = Person(firstName = "Alice", age = 30, email = "[email protected]") | ||
|
|
||
| demonstrateToString(person1, person2) | ||
| demonstrateToEquals(person1, person2, person3) | ||
| demonstrateToHashCode(person1, person2, person3) | ||
| demonstrateToCopy(person1) | ||
| demonstrateToDestructuring(person1) | ||
| } | ||
|
|
||
| fun demonstrateToString(person1: Person, person2: Person) { | ||
| // toString() - automatically generated | ||
| println("\n=== toString() ===") | ||
| println("Person 1: $person1") | ||
| println("Person 2: $person2") | ||
| // Output: | ||
| // Person 1: Person(firstName=Alice, age=30, [email protected]) | ||
| // Person 2: Person(firstName=Bob, age=32, [email protected]) | ||
| } | ||
|
|
||
| fun demonstrateToEquals(person1: Person, person2: Person, person3: Person) { | ||
| // equals() - automatically generated | ||
| println("\n=== equals() ===") | ||
| println("person1 == person3: ${person1 == person3}") // true | ||
| println("person1 == person2: ${person1 == person2}") // false | ||
| } | ||
|
|
||
| fun demonstrateToHashCode(person1: Person, person2: Person, person3: Person) { | ||
| // hashCode() - automatically generated | ||
| println("\n=== hashCode() ===") | ||
| println("person1.hashCode() equals person3.hashCode(): ${person1.hashCode() == person3.hashCode()}") // true | ||
|
|
||
| // Checking in HashSet | ||
| println("\n=== Checking in HashSet ===") | ||
| val peopleSet = hashSetOf(person1, person2) | ||
| println("set contains person1: ${peopleSet.contains(person1)}") // true | ||
| println("set contains person3: ${peopleSet.contains(person3)}") // true, because hashCode() and equals() are the same | ||
| // Output: | ||
| // set contains person1: true | ||
| // set contains person3: true | ||
|
|
||
| // Checking in HashMap | ||
| println("\n=== Checking in HashMap ===") | ||
|
|
||
| val salary = | ||
| hashMapOf( | ||
| person1 to 30000, | ||
| person2 to 27000, | ||
| ) | ||
|
|
||
| println("person1 salary: ${salary[person1]}") // 30000 | ||
| println("person3 salary: ${salary[person3]}") // 30000, because person3 equals person1 (same hashCode and equals) | ||
|
|
||
| // Important! The use "var" is not recommended in the data classes. | ||
| println("\n=== Mutation properties: ===") | ||
| val mutablePerson = MutablePerson("Charlie", 35, "[email protected]") | ||
| val roleMap = hashMapOf(mutablePerson to "Developer") | ||
| println("before mutation: ${mutablePerson.hashCode()}") | ||
| mutablePerson.age = 36 | ||
| println("after mutation: ${mutablePerson.hashCode()}") // Different! | ||
| println("Map size: ${roleMap.size}") // Map still contains the entry but can't find it. | ||
| } | ||
|
|
||
| fun demonstrateToCopy(person1: Person) { | ||
| // copy() - automatically generated. | ||
| // Attention! It is shallow copy. See example | ||
| println("\n=== copy() ===") | ||
|
|
||
| val person1Updated = person1.copy(age = 31, email = "[email protected]") | ||
|
|
||
| println("Updated person 1: $person1Updated") | ||
| // Output: Updated person 1: Person(firstName=Alice, age=31, [email protected]) | ||
|
|
||
| println("\n=== Shallow copy: ===") | ||
| val originalAddress = Address("New York", "Washington Street") | ||
| val employee1 = Employee("Developer", person1, originalAddress) | ||
| val employee2 = employee1.copy() | ||
| println("before mutation:") | ||
| println("employee1: $employee1") | ||
| println("employee2: $employee2") | ||
| // employee1: Employee(position=Developer, person=Person(firstName=Alice, age=30, [email protected]), address=Address(city=New York, street=Washington Street)) | ||
| // employee2: Employee(position=Developer, person=Person(firstName=Alice, age=30, [email protected]), address=Address(city=New York, street=Washington Street)) | ||
|
|
||
| employee2.address.street = "Park Avenue" | ||
| println("after mutation:") | ||
| println("employee1: $employee1") // The street has changed too! | ||
| println("employee2: $employee2") | ||
| // employee1: Employee(position=Developer, person=Person(firstName=Alice, age=30, [email protected]), address=Address(city=New York, street=Park Avenue)) | ||
| // employee2: Employee(position=Developer, person=Person(firstName=Alice, age=30, [email protected]), address=Address(city=New York, street=Park Avenue)) | ||
| } | ||
|
|
||
| fun demonstrateToDestructuring(person1: Person) { | ||
| // Destructuring - automatically generated componentN() functions corresponding to the properties in their order of declaration. | ||
| println("\n=== Destructuring: ===") | ||
| val (name, age, email) = person1 | ||
| println("Destructured: name=$name, age=$age, email=$email") | ||
| // Output: Destructured: name=Alice, age=30, [email protected] | ||
|
|
||
| // You can also use componentN() functions directly | ||
| println("name: ${person1.component1()}") | ||
| println("age: ${person1.component2()}") | ||
| println("email: ${person1.component3()}") | ||
| // Output: | ||
| // name: Alice | ||
| // age: 30 | ||
| // email: [email protected] | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # 🛠️ Kotlin Features | ||
|
|
||
| This package contains examples of **Kotlin features**. | ||
|
|
||
| Each feature is implemented in its own file and is tested with a corresponding unit test - keeping the code clean, minimal, and easy to understand. | ||
|
|
||
| Whether you're learning, referencing, or contributing - this collection is for you. | ||
|
|
||
| --- | ||
|
|
||
| ## 🗂️ Available Features | ||
|
|
||
| | Feature Name | Description | File | | ||
| |-----------------------|----------------------------|--------------------------------| | ||
| | Data classes | Kotlin data class features | [`DataClass.kt`](DataClass.kt) | | ||
| | _...more coming soon_ | | ||
|
|
||
| --- | ||
|
|
||
| ## 🙌 Want to Help? | ||
|
|
||
| - Check out the [issues labeled `type: kotlinfeature`](https://github.com/e5LA/kotlin-code-collection/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22type%3A%20kotlinfeature%22) | ||
| - Or submit your own idea as new [Issue](https://github.com/e5LA/kotlin-code-collection/issues/new)! |
146 changes: 146 additions & 0 deletions
146
src/test/kotlin/codecollection/kotlinfeatures/DataClassTest.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| package codecollection.kotlinfeatures | ||
|
|
||
| import kotlin.test.Test | ||
| import kotlin.test.assertEquals | ||
| import kotlin.test.assertNotEquals | ||
| import kotlin.test.assertNotSame | ||
| import kotlin.test.assertNull | ||
| import kotlin.test.assertSame | ||
| import kotlin.test.assertTrue | ||
|
|
||
| class DataClassTest { | ||
| val person1 = Person(firstName = "Alice", age = 30, email = "[email protected]") | ||
| val person2 = Person(firstName = "Bob", age = 32, email = "[email protected]") | ||
| val person3 = Person(firstName = "Alice", age = 30, email = "[email protected]") | ||
|
|
||
| val mutablePerson = MutablePerson("Charlie", 35, "[email protected]") | ||
|
|
||
| val address = Address("New York", "Washington Street") | ||
|
|
||
| val employee1 = Employee("Developer", person1, address) | ||
| val employeeDefault = Employee(person = person1, address = address) | ||
|
|
||
| @Test | ||
| fun `should create person with correct properties`() { | ||
| assertEquals("Alice", person1.firstName) | ||
| assertEquals(30, person1.age) | ||
| assertEquals("[email protected]", person1.email) | ||
| } | ||
|
|
||
| @Test | ||
| fun `toString() should return formatted string`() { | ||
| assertEquals( | ||
| "Person(firstName=Alice, age=30, [email protected])", | ||
| person1.toString(), | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun `equals should work correctly for same content`() { | ||
| assertEquals(person1, person3) | ||
| assertNotEquals(person1, person2) | ||
| } | ||
|
|
||
| @Test | ||
| fun `hashCode should be same for equal objects`() { | ||
| assertEquals(person1.hashCode(), person3.hashCode()) | ||
| assertNotEquals(person1.hashCode(), person2.hashCode()) | ||
| } | ||
|
|
||
| @Test | ||
| fun `should work correctly in hashset`() { | ||
| val peopleSet = hashSetOf(person1, person2) | ||
| assertTrue(peopleSet.contains(person1)) | ||
| assertTrue(peopleSet.contains(person2)) | ||
| assertTrue(peopleSet.contains(person3)) | ||
| assertEquals(2, peopleSet.size) | ||
| } | ||
|
|
||
| @Test | ||
| fun `should work correctly in hashmap`() { | ||
| val salary = | ||
| hashMapOf( | ||
| person1 to 30000, | ||
| person2 to 27000, | ||
| ) | ||
| assertEquals(30000, salary[person1]) | ||
| assertEquals(27000, salary[person2]) | ||
| assertEquals(30000, salary[person3]) | ||
| assertEquals(2, salary.size) | ||
| } | ||
|
|
||
| @Test | ||
| fun `mutation var properties should break hashmap key`() { | ||
| val testMap = hashMapOf(mutablePerson to "Developer") | ||
| assertEquals("Developer", testMap[mutablePerson]) | ||
| mutablePerson.age = 36 | ||
| assertNull(testMap[mutablePerson]) | ||
| } | ||
|
|
||
| @Test | ||
| fun `mutation var properties should change hashCode()`() { | ||
| val originalHashCode = mutablePerson.hashCode() | ||
| mutablePerson.age = 36 | ||
| val newHashCode = mutablePerson.hashCode() | ||
| assertNotEquals(originalHashCode, newHashCode) | ||
| } | ||
|
|
||
| @Test | ||
| fun `copy() should create new instance with identical properties`() { | ||
| val copy = person1.copy() | ||
| assertEquals(person1, copy) | ||
| assertNotSame(person1, copy) | ||
| } | ||
|
|
||
| @Test | ||
| fun `copy() should create new instance with updated properties`() { | ||
| val updated = person1.copy(email = "[email protected]") | ||
| assertEquals(person1.firstName, updated.firstName) | ||
| assertEquals(person1.age, updated.age) | ||
| assertEquals("[email protected]", updated.email) | ||
| assertEquals("[email protected]", person1.email) | ||
| } | ||
|
|
||
| @Test | ||
| fun `copy() should perform shallow copy of reference types`() { | ||
| val employee2 = employee1.copy() | ||
|
|
||
| assertNotSame(employee1, employee2) | ||
| assertSame(employee1.person, employee2.person) | ||
| assertSame(employee1.address, employee2.address) | ||
| } | ||
|
|
||
| @Test | ||
| fun `mutation of referenced objects should affect the original and its copy`() { | ||
| val employee2 = employee1.copy() | ||
| employee2.address.street = "Park Avenue" | ||
| assertEquals("Park Avenue", employee1.address.street) | ||
| assertEquals("Park Avenue", employee2.address.street) | ||
| } | ||
|
|
||
| @Test | ||
| fun `should use default value when not specified`() { | ||
| assertEquals("Intern", employeeDefault.position) | ||
| } | ||
|
|
||
| @Test | ||
| fun `copy() use default value`() { | ||
| val copiedEmployee = employeeDefault.copy() | ||
| assertEquals("Intern", copiedEmployee.position) | ||
| } | ||
|
|
||
| @Test | ||
| fun `destructuring should work correctly`() { | ||
| val (name, age, email) = person1 | ||
| assertEquals("Alice", name) | ||
| assertEquals(30, age) | ||
| assertEquals("[email protected]", email) | ||
| } | ||
|
|
||
| @Test | ||
| fun `componentN() should work correctly`() { | ||
| assertEquals("Alice", person1.component1()) | ||
| assertEquals(30, person1.component2()) | ||
| assertEquals("[email protected]", person1.component3()) | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.