I have the following method in Java:
public void doSomething() {
final boolean promote = false;
final String bob;
if (promote) {
try(StringWriter sw = new StringWriter()) {
sw.write("this is a test");
bob = sw.toString();
} catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException();
}
} else {
bob = "anaconda";
}
System.out.println(bob);
}
When I convert this to Kotlin:
val promote = false
val bob: String
if (promote) {
try {
StringWriter().use { sw ->
sw.write("this is a test")
bob = sw.toString()
}
} catch (e: IOException) {
e.printStackTrace()
throw IllegalStateException()
}
} else {
bob = "anaconda"
}
println(bob)
But I get a compiler error on the last line: Variable 'bob' must be initialized.
I can't see how Kotlin could fail to initialise the bob variable when the Java compiler is so sure that the variable has either been initialised or an exception has been thrown.
Is my only option to change bob to a var and initialise it?
Assign the result of use method to the variable like so:
bob = StringWriter().use { sw ->
sw.write("this is a test")
sw.toString()
}
The Java compiler is able to figure out that the variable will be initialised because the try with resources is a language feature. The use method on the other hand is a library feature with behavior dependent on the implementation that is actually imported and used. In other words the Kotlin compiler has no way of knowing if the function passed as an argument to use will be invoked immediately or not.
Related
On android app, Having a java function
JSONObject addToJson(#NonNull JSONObject jsonObject, #NonNull String key, boolean value){
try {
jsonObject.put(key, value);
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
test code, it throws when call the mock jsonObject.put(key, value) and works fine:
#Test
public void test_addToJson() throws JSONException {
JSONObject jsonObject = Mockito.spy(new JSONObject());
Mockito.when(jsonObject.put(anyString(), anyBoolean())).thenThrow(new JSONException("!!! test forced exception"));
JSONObject outputObject = addToJson(jsonObject, "null", true);
assertEquals("jsonobject length should match", 0, outputObject.length());
}
after convert to kotlin
fun addToJson(jsonObject: JSONObject, key: String, value: Boolean?): JSONObject {
try {
jsonObject.put(key, value)
} catch (e: JSONException) {
e.printStackTrace()
}
return jsonObject
}
the test is failing that no exception thrown.
The Java code uses the primitive type boolean for value. The Kotlin version is using the nullable type Boolean? which seems unnecessary since the parameter could never be null in the Java version.
The change to a nullable type might cause the anyBoolean matcher to fail. You could try switching to the non-nullable type Boolean, or keep using Boolean? and change the anyBoolean matcher to anyOrNull from mockito-kotlin.
Let's have a function which just computes something in try-catch and returns the result:
private fun compute(): String {
return try {
// do some computation
// ...
"result"
} catch(t: Throwable) {
throw RuntimeException("Uups") // <-- GOAL: extract this to a dedicated method
}
}
I would like to extract the throw declaration to a separate function (which contains the my boilerplate code).
However, I'm unable to compile such setup in Kotlin.
A simplistic (and still uncompilable) version of the described problem:
private fun compute(): String {
return try {
// do some computation
// ...
"result"
} catch(t: Throwable) {
justThrow() // <-- NOT COMPILABLE, STRING EXPECTED
}
}
#Throws(RuntimeException::class)
private fun justThrow() {
// some boilerplate code
// ...
throw RuntimeException("Uups")
}
How write justThrow() method in Kotlin so that the whole code is compilable?
In Java this case would be detected by a compiler (I suppose).
Kotlin version: 1.4.21
You can declare the return type of your method as Nothing. This type can be used for any method that does not return normally. That might be because it will always throw an exception, or simply never returns at all, for instance because it contains an infinite loop.
private fun justThrow(): Nothing {
// some boilerplate code
// ...
throw RuntimeException("Uups")
}
I'm trying to display emails of users stored in firebase database.
I've this below code
snapsListView = findViewById(R.id.snapsList)
val adapter = emails?.let { ArrayAdapter(this, android.R.layout.simple_list_item_1, it) }
snapsListView?.adapter = adapter
auth.currentUser?.uid?.let { FirebaseDatabase.getInstance().getReference().child("users").child(it).child("snaps").addChildEventListener(object: ChildEventListener{
override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
emails?.add(snapshot.child("from").value as String)
adapter?.notifyDataSetChanged()
try {
for(x in emails!!){
Log.i("Emails", x)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
Emails are present in the database and as per the hierrarchy also, users-> uid->snaps and snaps contains the email in "from"
Don't know what is causing this error, or how do i resolve this.
Always getting null pointer exception
By using !! operator you have asserted that emails is not null. However, Kotlin thrown runtime exception because emails is null actually. Consider replacing !! with safe-access:
emails?.let { for (x in it) Log.i("Emails", x) }
Running this on IntelliJ IDEA 2020.11 using JDK 14 and coding it in Kotlin.
I have a class with a variable menuComponents which is an ArrayList full of MenuComponents, but it's empty at initialization.
var menuComponents: ArrayList<MenuComponent> = ArrayList()
I want to edit the components so I wrote this.
for (component in menuComponents) {
//Do some stuff. The stuff doesn't matter, it throws an exception if I leave it blank
}
When I call on this method, I get a null pointer exception. Additionally, the for loop doesn't even matter.
class NPE() {
init {
refreshProperties()
}
var menuComponents: ArrayList<Double> = ArrayList()
fun refreshProperties() {
refreshJMenuComponents()
}
private fun refreshJMenuComponents() {
val i = menuComponents.size
println("$i is the length.")
for (index in 0 until menuComponents.size) {
val component = menuComponents[index]
println("Refreshed component: $component")
}
}
}
fun main() {
NPE()
}
This statement errors out too. I don't change menuComponents at all before I call these, so it should just be equal to a blank array list. I don't know why it's throwing a Null Pointer Exception.
menuComponents = arrayListOf(//component 1, component 2)
If I try running any of the previous statements on menuComponents now, it still throws a Null Pointer Exception. The value is not nullable, and I am explicitly setting it equal to something, so why is it erroring out at all? It should just not even compile if there is a null object somewhere? It compiles and then throws an exception.
Is this some sort of possible bug or am I just missing something?
I just needed to move the variable initialization above the init block.
class NPE() {
var menuComponents: ArrayList<Double> = ArrayList()
init {
refreshProperties()
}
fun refreshProperties() {
refreshJMenuComponents()
}
private fun refreshJMenuComponents() {
val i = menuComponents.size
println("$i is the length.")
for (index in 0 until menuComponents.size) {
val component = menuComponents[index]
println("Refreshed component: $component")
}
}
}
fun main() {
NPE()
}
I am a bit confused with throwing custom exceptions in Swift 3.
In C++ I can do this to immediately stop the process in the method, throw an error and handle it without proceeding further.
void foo()
{
try
{
if (a > b)
{
throw MyException();
}
DoOtherStaff();
}
catch (const MyException& e)
{
HandleError();
}
}
I am trying to implement something like this in Swift 3
enum MyError : Error
{
case myError(String)
}
func foo()
{
do
{
if (a > b)
{
throw MyError.myError("My error message");
}
DoOtherStaff();
}
catch
{
HandleError();
}
}
But it tells me me that the error is not handled because the enclosing catch is not exhaustive. Is there a way to handle it?
Thank you!
There is nothing wrong a priori with the code you showed. As a proof, just copy and paste the following into a playground (or into a class definition in an actual project):
enum MyError : Error {
case myError(String)
}
let a = 1
let b = 2
func foo() {
do {
if a > b {
throw MyError.myError("My error message")
}
doOtherStuff()
}
catch {
handleError()
}
}
func doOtherStuff() {}
func handleError() {}
That compiles and runs fine in the playground (though of course it doesn't do anything). Observe that all I did different from the code you gave was to "fill in the blanks", i.e. provide declarations of all the terms you referred to.