42

Imagine I have a Kotlin program with a variable b of type Byte, into which an external system writes values greater than 127. "External" means that I cannot change the type of the value it returns.

val a:Int = 128 val b:Byte = a.toByte()

Both a.toByte() and b.toInt() return -128.

Imagine I want to get the correct value (128) from the variable b. How can I do it?

In other words: What implementation of magicallyExtractRightValue would make the following test run?

@Test
fun testByteConversion() {
    val a:Int = 128
    val b:Byte = a.toByte()

    System.out.println(a.toByte())
    System.out.println(b.toInt())

    val c:Int = magicallyExtractRightValue(b)

    Assertions.assertThat(c).isEqualTo(128)
}

private fun magicallyExtractRightValue(b: Byte): Int {
    throw UnsupportedOperationException("not implemented")
}

Update 1: This solution suggested by Thilo seems to work.

private fun magicallyExtractRightValue(o: Byte): Int = when {
    (o.toInt() < 0) -> 255 + o.toInt() + 1
    else -> o.toInt()
}
Community
  • 1
  • 1
Glory to Russia
  • 17,289
  • 56
  • 182
  • 325
  • `byte` is signed in Java, so you will have to live with this. Why do you have to use a `byte`? Where is the `int` coming from? – Thilo Jul 29 '16 at 05:42
  • I have an external library, which I don't want to change. It gives me byte-typed values with negative numbers in them. – Glory to Russia Jul 29 '16 at 05:44
  • so the library already gives you "-127". Why do you need to convert it? It does not make a difference unless you use it numerically. If you are sure the library really "meant" 128 instead, you could use `short` or `int` on your end of things (convert by doing 255 + b for negative numbers). – Thilo Jul 29 '16 at 05:46
  • I need the actual numerical value, because in another third-party library that numerical value is used as an index in an array. – Glory to Russia Jul 29 '16 at 05:49
  • 3
    Array indexes are `int`. You can convert from your "unsigned byte" by doing `int x = b < 0 ? 255 + b : b;` – Thilo Jul 29 '16 at 05:53
  • http://stackoverflow.com/questions/4266756/can-we-make-unsigned-byte-in-java – Thilo Jul 29 '16 at 05:54
  • Thanks. If you submit your comment as an answer, I'll accept it. See also my update 1. – Glory to Russia Jul 29 '16 at 05:59
  • I couldn't find it before but here is a related question: http://stackoverflow.com/q/2640946/3255152. – mfulton26 Aug 01 '16 at 14:05

2 Answers2

75

With Kotlin 1.3+ you can use unsigned types. e.g. toUByte (Kotlin Playground):

private fun magicallyExtractRightValue(b: Byte): Int {
    return b.toUByte().toInt()
}

or even require using UByte directly instead of Byte (Kotlin Playground):

private fun magicallyExtractRightValue(b: UByte): Int {
    return b.toInt()
}

For releases prior to Kotlin 1.3, I recommend creating an extension function to do this using and:

fun Byte.toPositiveInt() = toInt() and 0xFF

Example usage:

val a: List<Int> = listOf(0, 1, 63, 127, 128, 244, 255)
println("from ints: $a")
val b: List<Byte> = a.map(Int::toByte)
println("to bytes: $b")
val c: List<Int> = b.map(Byte::toPositiveInt)
println("to positive ints: $c")

Example output:

from ints: [0, 1, 63, 127, 128, 244, 255]
to bytes: [0, 1, 63, 127, -128, -12, -1]
to positive ints: [0, 1, 63, 127, 128, 244, 255]
mfulton26
  • 29,956
  • 6
  • 64
  • 88
0

Good old printf does what we want:

java.lang.String.format("%02x", byte)
Raphael
  • 9,779
  • 5
  • 63
  • 94