-
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 = "alice@example.com") | ||
| val person2 = Person(firstName = "Bob", age = 32, email = "bob@example.com") | ||
| val person3 = Person(firstName = "Alice", age = 30, email = "alice@example.com") | ||
|
|
||
| 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=alice@example.com) | ||
| // Person 2: Person(firstName=Bob, age=32, email=bob@example.com) | ||
| } | ||
|
|
||
| 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, "charlie@example.com") | ||
| 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 = "new.alice@example.com") | ||
|
|
||
| println("Updated person 1: $person1Updated") | ||
| // Output: Updated person 1: Person(firstName=Alice, age=31, email=new.alice@example.com) | ||
|
|
||
| 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=alice@example.com), address=Address(city=New York, street=Washington Street)) | ||
| // employee2: Employee(position=Developer, person=Person(firstName=Alice, age=30, email=alice@example.com), 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=alice@example.com), address=Address(city=New York, street=Park Avenue)) | ||
| // employee2: Employee(position=Developer, person=Person(firstName=Alice, age=30, email=alice@example.com), 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=alice@example.com | ||
|
|
||
| // 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: alice@example.com | ||
| } | ||
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 = "alice@example.com") | ||
| val person2 = Person(firstName = "Bob", age = 32, email = "bob@example.com") | ||
| val person3 = Person(firstName = "Alice", age = 30, email = "alice@example.com") | ||
|
|
||
| val mutablePerson = MutablePerson("Charlie", 35, "charlie@example.com") | ||
|
|
||
| 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("alice@example.com", person1.email) | ||
| } | ||
|
|
||
| @Test | ||
| fun `toString() should return formatted string`() { | ||
| assertEquals( | ||
| "Person(firstName=Alice, age=30, email=alice@example.com)", | ||
| 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 = "new.alice@example.com") | ||
| assertEquals(person1.firstName, updated.firstName) | ||
| assertEquals(person1.age, updated.age) | ||
| assertEquals("new.alice@example.com", updated.email) | ||
| assertEquals("alice@example.com", 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("alice@example.com", email) | ||
| } | ||
|
|
||
| @Test | ||
| fun `componentN() should work correctly`() { | ||
| assertEquals("Alice", person1.component1()) | ||
| assertEquals(30, person1.component2()) | ||
| assertEquals("alice@example.com", 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.