Long java сколько цифр
Перейти к содержимому

Long java сколько цифр

  • автор:

Примитивные типы в Java: Не такие уж они и примитивные

Java-университет

Примитивные типы в Java: Не такие уж они и примитивные - 1

Разработку приложений можно рассматривать как работу с некоторыми данными, а точнее — их хранение и обработку. Сегодня хотелось бы затронуть первый ключевой аспект. Как данные хранятся в Java? Тут у нас есть два возможные формата: ссылочный и примитивный тип данных. Давайте поговорим о видах примитивных типов и возможностях работы с ними (как ни крути, это фундамент наших знаний языка программирования). Примитивные типы данных Java — это основа, на которой держится всё. Нет, я нисколько не преувеличиваю. У Oracle примитивам посвящён отдельный Tutorial: Primitive Data TypesНемного истории. Вначале был ноль. Но ноль — это скучно. И тогда появился bit (бит). Почему его так назвали? Назвали его так от сокращения «binary digit» (двоичное число). То есть у него есть только два значения. А так как был ноль, то логично, что теперь стало или 0 или 1. И стало жить веселее. Биты начали собираться в стаи. И эти стаи стали называть byte (байт). В современном мире byte = 2 в третьей степени, т.е. 8. Но, оказывается, так было не всегда. Существует множество догадок, легенд и слухов, откуда пошло название byte. Кто-то считает, что всё дело в кодировках того времени, а кто-то считает, что так было выгоднее считать информацию. Байт — это наименьшая адресуемая часть памяти. Именно байты имеют уникальные адреса в памяти. Есть легенда о том, что ByTe это сокращение от Binary Term — машинное слово. Машинное слово – если говорить просто, это количество данных, которые процессор может обработать за одну операцию. Раньше размер машинного слова совпадал с наименьшей адресуемой памятью. В Java, переменные могут хранить только значение байтов. Как я и говорил выше, в Java существует два вида переменных:

  • примитивные типы java, хранят непосредственно значение байтов данных (подробнее типы этих примитивов мы разберем немного ниже);
  • ссылочный тип, хранит байты адреса объекта в Heap, то есть через эти переменные мы получаем доступ непосредственно к самому объекту(такой себе пульт от объекта)

Java byte

Итак, история подарила нам байт – минимальный объём памяти, который мы можем использовать. И состоит он из 8 бит. Самый маленький целый тип данных в java – byte. Это знаковый 8-битовый тип. Что это значит? Давайте считать. 2 ^ 8 будет 256. Но что же делать, если мы хотим отрицательное число? И решили разработчики Java, что двоичный код «10000000» будет обозначать -128, то есть старший бит (самый левый бит) будет обозначать, отрицательное ли число. Двоичное «0111 1111» равняется 127. То есть 128 никак не обозначить, т.к. это будет -128. Полный расчёт приведён в этом ответе: Why is the range of bytes -128 to 127 in Java? Чтобы понять как получаются числа, стоит посмотреть на картинку:

Примитивные типы в Java: Не такие уж они и примитивные - 2

Соответственно, чтобы вычислить размер 2^(8-1) = 128. Значит минимальная граница (а она с минусом) будет -128. А максимальная 128 – 1 (вычитаем ноль). То есть максимум будет 127. На самом деле, с типом byte работаем мы не так часто на «высоком уровне». В основном это обработка «сырых» данных. Например, при работе с передачей данных по сети, когда данные это набор 0 и 1, переданных через какой-то канал связи. Или при чтении данных из файлов. Так же могут быть использованы при работе со строкам и кодировками. Пример кода:

 public static void main(String []args) < byte value = 2; byte shortByteValue = 0b10; // 2 System.out.println(shortByteValue); // Начиная с JDK7 мы можем разделять литералы подчёркиваниями byte minByteValue = (byte) 0B1000_0000; // -128 byte maxByteValue = (byte) 0b0111_1111; // 127 byte minusByteValue = (byte) 0b1111_1111; // -128 + 127 System.out.println(minusByteValue); System.out.println(minByteValue + " to " + maxByteValue); >

Кстати, не стоит думать, что использование типа byte будет снижать потребление памяти. В основном byte используется для уменьшения расхода памяти при хранении данных в массивах (например, хранение данных, полученных по сети в некотором буфере, который будет реализован в виде массива байт). А вот при операциях над данными использование byte не оправдает ваши ожидания. Связано это с реализацией Java Virtual Machine (JVM). Так как большинство систем 32 или 64 разрядные, то byte и short при вычислениях будут приведены к 32-битному int, о котором мы поговорим дальше. Так проще производить вычисления. Подробнее см. Is addition of byte converts to int because of java language rules or because of jvm?. В ответе даны так же ссылки на JLS (Java Language Specification). Кроме того, использование byte в неправильном месте может привести к неловким моментам:

 public static void main(String []args) < for (byte i = 1; i > 

Тут будет зацикливание. Потому что значение счётчика дойдёт до максимума (127), произойдёт переполнение и значение станет -128. И мы никогда не выйдем из цикла.

short

Лимит значений из byte довольно мал. Поэтому, для следующего типа данных решили увеличить количество бит вдвое. То есть теперь не 8 бит, а 16. То есть 2 байта. Значения можно посчитать так же. 2^(16-1) = 2 ^ 15 = 32768. Значит, диапазон от -32768 до 32767. Используют его совсем редко для каких-либо специальных случаев. Как говорит нам документация языка Java: «you can use a short to save memory in large arrays».

int

Вот мы и добрались до самого частоиспользуемого типа. Занимает он 32 бита, или 4 байта. В общем, мы продолжаем удваивать. Диапазон значений от -2^31 до 2^31 – 1.

Максимальное значение int

Максимальное значение int 2147483648 – 1, что совсем не мало. Как выше было указано, для оптимизации вычислений, т.к. современным компьютерам с учетом их разрядности удобнее считать, данные могут быть неявно преобразованы к int. Вот простой пример:

 byte a = 1; byte b = 2; byte result = a + b; 

Такой безобидный код, а мы получим ошибку: «error: incompatible types: possible lossy conversion from int to byte». Придётся исправить на byte result = (byte)(a + b); И ещё один безобидный пример. Что будет если запустим следующий код?

 int value = 4; System.out.println(8/value); System.out.println(9/value); System.out.println(10/value); System.out.println(11/value); 

А мы получим вывод

 2 2 2 2 

*звуки паники* Дело обстоит в том, что при работе с int значениями остаток отбрасывается, оставляя только целую часть(в таких случая лучше уж использовать double).

long

Продолжаем удваивать. 32 умножаем на 2 и получаем 64 бита. По традиции, это 4 * 2, то есть 8 байт. Диапазон значений от -2^63 до 2^63 – 1. Более чем достаточно. Данный тип позволяет считать большие-большие числа. Часто используется при работе со временем. Или с большими расстояниями, например. Для обозначения того, что число это long после числа ставят литерал L – Long. Пример:

 long longValue = 4; longValue = 1l; // Не ошибка, но плохо читается longValue = 2L; // Идеально 

Хочется забежать вперёд. Далее мы будем рассматривать тот факт, что для примитивов есть соответствующие обёртки, которые дают возможность работать с примитивами как с объектами. Но есть интересная особенность. Вот пример: На том же Tutorialspoint online compiler можете проверить такой вот код:

 public class HelloWorld < public static void main(String []args) < printLong(4); >public static void printLong(long longValue) < System.out.println(longValue); >> 

Данный код работает без ошибок, всё хорошо. Но стоит в методе printLong заменить тип с long на Long (т.е. тип становится не примитивным, а объектным), как становится джаве непонятно, какой параметр мы передаём. Она начинает считать, что передаётся int и будет ошибка. Поэтому, в случае с методом необходимо будет явно указывать 4L. Очень часто long используется как ID при работе с базами данных.

Java float и Java double

Данные типы называются типами с плавающей точкой. То есть это не целочисленные типы. Тип float является 32битным (как int), а double называется типом с двойной точностью, поэтому он 64битный (умножаем на 2, всё как мы любим). Пример:

 public static void main(String []args) < // float floatValue = 2.3; lossy conversion from double to float float floatValue = 2.3F; floatValue = 2.3f; double doubleValue = 2.3; System.out.println(floatValue); double cinema = 7D; >

А вот пример разницы значений (из-за точности типов):

 public static void main(String []args)

Данные примитивные типы используются в математике, например. Вот доказательство, константа для вычисления числа PI. Ну и вообще можно посмотреть API класса Math. Вот что ещё должно быть важно и интересно: даже в документации сказано: «This data type should never be used for precise values, such as currency. For that, you will need to use the java.math.BigDecimal class instead.Numbers and Strings covers BigDecimal and other useful classes provided by the Java platform.». То есть деньги в float и double не надо вычислять. Пример про точность на примере работы в NASA: Java BigDecimal, Dealing with high precision calculations Ну и чтобы самим прочувствовать:

 public static void main(String []args)

Выполните этот пример, а потом добавьте 0 перед цифрами 5 и 4. И вы увидите весь ужас) Есть интересный доклад на русском про float и double в тему: https://youtu.be/1RCn5ruN1fk Примеры работы с BigDecimal можно увидеть здесь: Make cents with BigDecimal Кстати, float и double могут вернуть не только число. Например, пример ниже вернёт Infinity (т.е. бесконечность):

 public static void main(String []args) < double positive_infinity = 12.0 / 0; System.out.println(positive_infinity); >

А этот вернёт NAN:

 public static void main(String []args) < double positive_infinity = 12.0 / 0; double negative_infinity = -15.0 / 0; System.out.println(positive_infinity + negative_infinity); >

Про бесконечность понятно. А что такое NaN? Это Not a number, то есть результат не может быть высчитан и не является числом. Вот пример: Мы хотим вычислить квадратный корень из -4. Квадратный корень из 4 это 2. То есть 2 надо возвести квадрат и тогда мы получим 4. А что надо возвести в квадрат, чтобы получить -4? Не получится, т.к. если положительное число будет, то оно и останется. А если было отрицательное, то минус на минус даст плюс. То есть это не вычисляемо.

 public static void main(String []args) < double sqrt = Math.sqrt(-4); System.out.println(sqrt + 1); if (Double.isNaN(sqrt)) < System.out.println("So sad"); >System.out.println(Double.NaN == sqrt); > 

Вот ещё отличный обзор на тему чисел с плавающей точкой: Где ваша точка?

Java boolean

Следующий тип – булевский (логический тип). Он может принимать значения только true или false, которые являются ключевыми словами. Используется в логических операциях, таких как циклы while, и в ветвлении при помощи if, switch. Что тут можно интересного узнать? Ну, например, теоретически, нам достаточно 1 бита информации, 0 или 1, то есть true или false. Но на самом деле Boolean будет занимать больше памяти и это будет зависеть от конкретной реализации JVM. Обычно на это тратится столько же, сколько на int. Как вариант – использовать BitSet. Вот краткое описание из книги «Основы Java»: BitSet

Java char

  • Таблица Unicode символов
  • Таблица символов ASCII

Примитивные типы в Java: Не такие уж они и примитивные - 3

Пример в студию:

 public static void main(String[] args) < char symbol = '\u0066'; // Unicode symbol = 102; // ASCII System.out.println(symbol); >

Кстати, char, являясь по своей сути всё таки числом, поддерживает математические действия, такие как сумма. А иногда это может привести к забавным последствиям:

 public class HelloWorld < public static void main(String []args)< String costForPrint = "5$"; System.out.println("Цена только для вас " + + costForPrint.charAt(0) + getCurrencyName(costForPrint.charAt(1))); >public static String getCurrencyName(char symbol) < if (symbol == '$') < return " долларов"; >else < throw new UnsupportedOperationException("Not implemented yet"); >> > 

Настоятельно советую проверить в онлайн IDE от tutorialspoint. Когда я увидел этот пазлер на одной из конференций мне это подняло настроение. Надеюсь, Вам пример тоже понравится) UPDATED: Это было на Joker 2017, доклад: «Java Puzzlers NG S03 — Откуда вы все лезете-то?!».

Литералы

  • Десятеричная система: 10
  • Шестнадцатеричная система: 0x1F4, начинается с 0x
  • Восьмеричная система: 010, начинается с нуля.
  • Двоичная система (начиная с Java7): 0b101, начинается с 0b
 int costInDollars = 08; 

Эта строчка кода не скомпилируется:

 error: integer number too large: 08 

Кажется, что за бред. А теперь вспомним про двоичную и восьмеричную системы. В двоичной системе нет двойки, т.к. есть два значения (начиная с 0). А восьмеричной системе есть 8 значений, начиная с нуля. То есть самого значения 8 нет. Поэтому и ошибка, которая на первый взгляд кажется абсурдной. И чтобы вспомнить вот «вдогонку» правила перевода значений:

Примитивные типы в Java: Не такие уж они и примитивные - 4

Классы-обертки

Примитивные типы в Java: Не такие уж они и примитивные - 5

Примитивы в Java имеют свои классы-обертки, чтобы можно было работать с ними как с объектами. То есть, для каждого примитивного типа существует, соответствующий ему ссылочный тип. Классы-обертки являются immutable (неизменяемыми): это означает, что после создания объекта его состояние — значение поля value — не может быть изменено. Классы-обертки задекларированы как final: объекты, так сказать, read-only. Также хотелось бы упомянуть, что от этих классов невозможно наследоваться. Java автоматически делает преобразования между примитивными типами и их обертками:

 Integer x = 9; // autoboxing int n = new Integer(3); // unboxing 

Процесс преобразования примитивных типов в ссылочные (int->Integer) называется autoboxing (автоупаковкой), а обратный ему — unboxing (автораспаковкой). Эти классы дают возможность сохранять внутри объекта примитив, а сам объект будет вести себя как Object (ну как любой другой объект). При всём этом мы получаем большое количество разношерстных, полезных статических методов, как например — сравнение чисел, перевод символа в регистр, определение того, является ли символ буквой или числом, поиск минимального числа и т.п. Предоставляемый набор функционала зависит лишь от самой обертки. Пример собственной реализации обёртки для int:

 public class CustomerInt < private final int value; public CustomerInt(int value) < this.value = value; >public int getValue() < return value; >> 

В основном пакете, java.lang, уже есть реализации классы Boolean, Byte, Short, Character, Integer, Float, Long, Double, и нам не нужно ничего городить своего, а только переиспользовать готовое. К примеру, такие классы дают нам возможность создать, скажем, List , ведь List должен содержать только объекты, чем примитивы не являются. Для преобразования значения примитивного типа есть статические методы valueOf, например, Integer.valueOf(4) вернёт объект типа Integer. Для обратного преобразования есть методы intValue(), longValue() и т. п. Компилятор вставляет вызовы valueOf и *Value самостоятельно, это и есть суть autoboxing и autounboxing. Как выглядит пример автоупаковки и автораспаковки, представленный выше, на самом деле:

 Integer x = Integer.valueOf(9); int n = new Integer(3).intValue(); 

Подробнее про автоупаковку и автораспаковку можно почитать вот в этой статье.

Приведение типов

При работе с примитивами существует такое понятие как приведение типов, одно из не очень приятных свойств C++, тем не менее приведение типов сохранено и в языке Java. Иногда мы сталкиваемся с такими ситуациями, когда нам нужно совершать взаимодействия с данными разных типов. И очень хорошо, что в некоторых ситуациях это возможно. В случае с ссылочными переменными, там свои особенности, связанные с полиморфизмом и наследованием, но сегодня мы рассматриваем простые типы и соответственно приведение простых типов. Существует преобразование с расширением и преобразование сужающее. Всё на самом деле просто. Если тип данных становится больше (допустим, был int, а стал long), то тип становится шире (из 32 бит становится 64). И в этом случае мы не рискуем потерять данные, т.к. если влезло в int, то в long влезет тем более, поэтому данное приведение мы не замечаем, так как оно осуществляется автоматически. А вот в обратную сторону преобразование требует явного указания от нас, данное приведение типа называется — сужение. Так сказать, чтобы мы сами сказали: «Да, я даю себе отчёт в этом. В случае чего — виноват сам».

 public static void main(String []args)

Чтобы потом в таком случае не говорили что «Ваша Джава плохая», когда получат внезапно -128 вместо 128 ) Мы ведь помним, что в байте 127 верхнее значение и всё что находилось выше него соответственно можно потерять. Когда мы явно превратили наш int в байт, то произошло переполнение и значение стало -128.

Область видимости

Примитивные типы в Java: Не такие уж они и примитивные - 6

Это то место в коде, где данная переменная будет выполнять свои функции и хранить в себе какое-то значение. Когда же эта область закончится, переменная перестанет существовать и будет стерта из памяти и. как уже можно догадаться, посмотреть или получить ее значение будет невозможно! Так что же это такое — область видимости? Область определяется «блоком» — вообще всякой областью, замкнутой в фигурные скобки, выход за которые сулит удаление данных объявленных в ней. Или как минимум — сокрытие их от других блоков, открытых вне текущего. В Java область видимости определяется двумя основными способами:

  • Классом.
  • Методом.

Как я и сказал, переменная не видна коду, если она определена за пределами блока, в котором она была инициализирована. Смотрим пример:

 int x; x = 6; if (x >= 4) < int y = 3; >x = y;// переменная y здесь не видна! 

И как итог мы получим ошибку:

 Error:(10, 21) java: cannot find symbol symbol: variable y location: class com.javaRush.test.type.Main 

Области видимости могут быть вложенными (если мы объявили переменную в первом, внешнем блоке, то во внутреннем она будет видна).

Заключение

  • Целые числа: byte, short, int, long — представляют собой целые числа со знаком.
  • Числа с плавающей точкой — эта группа включает себе float и double — типы, которые хранят числа с точностью до определённого знака после запятой.
  • Булевы значения — boolean — хранят значения типа «истина/ложь».
  • Символы — в эту группу входит типа char.

Типы

Вселенная Java состоит из трёх субстанций: примитивы, объекты и коты. Про последних в документации ничего не говорится, поэтому их рассматривать не будем, но они существуют!

Примитивные типы Java не являются объектами. К ним относятся:

  • boolean — булев тип, может иметь значения true или false
  • byte — 8-разрядное целое число
  • short — 16-разрядное целое число
  • int — 32-разрядное целое число
  • long — 64-разрядное целое число
  • char — 16-разрядное беззнаковое целое, представляющее собой символ UTF-16 (буквы и цифры)
  • float — 32-разрядное число в формате IEEE 754 с плавающей точкой
  • double — 64-разрядное число в формате IEEE 754 с плавающей точкой

Примитивный в данном случае не оскорбление, а просто даёт понять, что речь идёт о простом типе, который не умеет прыгать, спать или мяукать. Да что он вообще умеет? Ой, всё.

Простые числовые типы

Тип Разрядность MIN MAX
byte 8 бит -128 127
short 16 бит -32768 32767
int 32 бит -2147483648 2147483647
long 64 бит -9223372036854775808 9223372036854775807
float 32 бит -3.4E+38 3.4E+38
double 64 бит -1.7E+308 1.7E+308

Целочисленные типы

Java определяет четыре целочисленных типа: byte, short, int, long. Они могут быть положительными и отрицательными (Java не поддерживает только положительные значения без знака, как некоторые языки программирования).

Тип byte

Наименьший по размеру целочисленный тип — byte. Это 8-битовый тип с диапазоном допустимых значений от -128 до 127. Переменные типа byte часто используются при работе с потоком данных из сети или файла, а также при работе с необработанными двоичными данными или в массивах для экономии памяти.

Объявить переменную типа byte можно следующим образом:

 byte c, a, t; // объявили сразу три переменные 

В арифметических выражениях с переменными типа byte вычисления выполняются как с типом int, т.е. с помощью 32-битовой арифметики, а полученный результат будет 32-битовым. Смотри пример с short.

Строку с числом перевести в данный тип можно через метод parseByte(String):

 byte x = Byte.parseByte("100"); 

Класс Byte является оболочкой для данного типа. Без необходимости не используйте в Android класс Byte.

Слово «байт» (byte) возникло в компании IBM примерно в 1956 году. Оно произошло от слова bite («кусок»), но его было решено писать через букву y, чтобы не путать со словом «bit» («бит»). В течение некоторого времени слово «байт» обозначало просто число битов в конкретном потоке данных. Однако в середине 1960-х, в связи с разработкой семейства компьютеров System/360 в компании IBM, это слово стало обозначать группу из восьми бит.

Любопытно, что bite имеет также значение «укус» (сущ.) или «укусить» (глагол). Таким образом это наш родной «Кусь!»

Cat

Тип short

Тип short — 16-битовый тип в диапазоне от -32768 до 32767. Используется очень редко.

 short m; 

В арифметических выражениях с переменными типа short вычисления выполняются как с типом int, т.е. с помощью 32-битовой арифметики, а полученный результат будет 32-битовым. Например, такой код не пройдёт.

 // накорми кота short fishNumber = 3; // три рыбки short beefNumber = 2; // два кусочка говядины short breakfast = 0; breakfast = fishNumber + beefNumber; // завтрак чемпиона 

Java будет ругаться на последнюю строчку, так как итоговый результат не может быть short. Как вариант, вам нужно преобразовать результат снова в 16-битовое число.

 breakfast = (short) (fishNumber + beefNumber); // завтрак чемпиона 

Явно перевести строку с числом в тип short можно через метод parseShort(String):

 short x = Short.parseShort("100"); 

Класс Short является оболочкой для данного типа. Без необходимости не используйте в Android класс Short.

Тип int

Целые числа, представленные типом int, являются самым распространённым типом в программе, с которым вы будете работать. Поэтому нужно хорошенько изучить его и узнать его достоинства и ограничения. Это 32-битовый тип, имеющий диапазон допустимых значений от -2147483648 до 2147483647 (около двух миллиардов). Этого числа вполне достаточно, чтобы посчитать всех котов на свете. Часто используется в циклах, индексировании массивов, хотя может показаться, что для небольших операций в цикле и массивах проще использовать short или byte. Нужно запомнить, что тип int эффективен в этих случаях из-за особенностей структуры вычислительных процессоров. Просто примите на веру.

Сказка про тип int

Зададим себе вопрос, насколько большим может быть целое число типа int?

Напишем простую программу, где будем умножать переменную саму на себя. Для начала присвоим ей значение 2, а дальше строчка за строчкой будем выводить результат. Результаты будем отдавать коту учёному LogCat. Весь код поместим в обработчик события щелчка на кнопке нашей учебной программы, а первую строчку поместим выше её.

 final String TAG = "ExpressCourse"; public void onClick(View view)

Запустите программу и нажмите кнопку. В нижней части студии откройте панель Android Monitor и в ней вкладку logcat. Настройте его фильтр, чтобы отображались только наши сообщения. В результате мы получим такую картину:

2 4 16 256 65536 0 0 0 0

Странные результаты типа Integer

Что за бред, скажете вы. Когда мы умножаем 65536 на себя, то получаем 0 (Только не говорите об этом учительнице по математике). А потом, естественно, программа умножает 0 на 0 и продолжает выводить результаты.

Вы ещё больше удивитесь, если в качестве начального значения возьмёте число 3. На этот раз вы сможете получить даже отрицательные значения.

3 9 81 6561 43046721 -501334399 2038349057 -1970898431 120648705

Проверьте самостоятельно. Если вы и это попытаетесь доказать учительнице, то исключение из учебного заведения вам гарантировано.

Деление целочисленных чисел

Запомните, что при делении целочисленных чисел остаток отбрасывается. Поэтому следующие примеры вернут один и тот же результат. Бедная учительница, её увезут в психушку.

 6 / 3 = 2 7 / 3 = 2 8 / 3 = 2 9 / 3 = 3 

На ноль делить нельзя, увидите ошибку.

Если нужен узнать остаток от деления, то используйте оператор % (оператор деления по модулю).

 Log.d(TAG, "Остаток 6 % 3: " + 6 % 3); // 0 Log.d(TAG, "Остаток 7 % 3: " + 7 % 3); // 1 Log.d(TAG, "Остаток 8 % 3: " + 8 % 3); // 2 Log.d(TAG, "Остаток 9 % 3: " + 9 % 3); // 0 

Класс Integer является оболочкой для данного типа. Без необходимости не используйте в Android класс Integer. Для сравнения: тип int занимает 4 байт памяти, а Integer — 16 байт.

Также есть специальный класс BigInteger для проведения арифметических действий повышенной точности (финансовые расчёты).

В Java 7 можно использовать знак подчёркивания для удобства. Например, так:

 int myInt = 1_000_000; // миллион 

Компилятор не обращает внимания на эти знаки, а человеку проще понять, что ему предлагают миллион или миллиард. В Android относительно недавно появилась полноценная поддержка Java 7 и вам в настройках нужно указать новую версию компилятора.

Этот приём относится не только к int, но и к другим типам чисел.

Как сконвертировать строку или CharSequence в int?
 String mString = "42"; // строка int mInt = Integer.parseInt(mString); 

Если у вас тип CharSequence, то его можно сконвертировать сначала в строку при помощи метода toString(), а потом в int.

Метод parseInt() предпочтительнее метода valueOf():

 int number; // плохой вариант number2 = Integer.valueOf("1"); // отличный вариант number = Integer.parseInt("1"); 
Как сконвертировать число в строку?

Если сложить число и строку, то Java автоматически конвертирует число в строку. Пользуясь этим свойством, программисты часто прибавляют к числу пустую строку. Но лучше использовать метод valueOf():

 int number = 1; // плохой вариант String numberString = "" + number; // отличный вариант String numberString = String.valueOf(number); 
Добавить ведущие нули

Если мы хотим получить строку из числа, добавим при этом несколько нулей вначале, то поможет метод format(), только учитывайте число цифр в самом числе.

 int givenNumber = 777; String formattedNumber = String.format("%06d", givenNumber); System.out.println("Число с ведущими нулями: " + formattedNumber); // Число с ведущими нулями: 000777 

Тип long

Тип long — это 64-битный тип со знаком, используемый в тех случаях, когда используется очень большое значение, которое не способен хранить тип int. Например, чтобы вычислить расстояние, которое прошёл солнечный луч от солнца до зеркала, превратившись в солнечного зайчика, за которым безуспешно охотится котёнок, вам понадобится именно этот тип.

Можно использовать символы l или L для обозначения числа типа long. Рекомендую использовать заглавную букву, чтобы избежать возможной путаницы. Например, напишем пример:

 // сколько ночей в арабских сказках? long night = 101l; System.out.println(night); 

Запустив пример, вы увидите ответ 101. Почему так получилось? А потому что последний символ — это не единица, а символ l. Присмотритесь внимательнее. Если бы мы написали long night = 101L, то не ломали бы голову себе.

Конвертируем строку в данный тип.

 long x = Long.parseLong("100"); 

Класс Long является оболочкой для данного типа. Без необходимости не используйте в Android класс Long.

Типы с плавающей точкой

Числа с плавающей точкой (иногда их называют действительными числами) применяются при вычислении выражений, в которых требуется точность до десятичного знака. Например, это может быть вычисление квадратного корня, значений синуса, косинуса и т.п. Существует два типа с плавающей точкой: float и double, которые представляют числа одинарной и двойной точности.

Слово «плавающая» означает, что десятичная точка может располагаться в любом месте (она «плавает»). Вот коты плавать не особенно любят, поэтому они не float и не double.

Тип float

Тип float определяет значение одинарной точности, которое занимает 32 бит. Переменные данного типа удобны, когда требуется дробная часть без особой точности, например, для денежных сумм.

Рекомендуется добавлять символ F или f для обозначения этого типа, иначе число будет считаться типом double.

 float tugrik = 11.6F; 

Конвертируем из строки.

 float x = Float.parseFloat("19.95"); 

Класс Float является оболочкой для данного типа. Без необходимости не используйте в Android класс Float.

Также есть специальный класс BigDecimal для проведения арифметических действий повышенной точности (финансовые расчёты).

Тип double

Тип double обеспечивает двойную точность, что видно из его названия (double — двойная). Занимает 64 бит для хранения значений. Многие математические функции возвращают значения типа double. Кстати, современные процессоры оптимизированы под вычисления значений двойной точности, поэтому они предпочтительнее, чем тип float.

 double pi, r, a; pi = 3.1416; // приблизительное значение числа π r = 5.5; // радиус окружности a = pi * r * r; // вычисляем площадь окружности 

Тип double содержит не только числа, но и слова. Сейчас вам докажу. Разделим число типа double на ноль. Ошибки не произойдёт.

 double positive_infinity = 12.0 / 0; System.out.println(positive_infinity); 

Пример вернёт значение Infinity (Бесконечность). Если разделить отрицательное число на ноль, то вернётся -Infinity.

А что произойдёт, если сложить две бесконечности? Если рассуждать логически, то сломается интернет, наступит конец света или можно вызвать Волдеморта. Я долго не решался, но потом набрался храбрости и попробовал.

 double positive_infinity = 12.0 / 0; double negative_infinity = -15.0 / 0; mInfoTextView.setText(String.valueOf(positive_infinity + negative_infinity)); 

Вернулось ещё одно слово — NaN. Что это вообще? Может должно вернуться Nyan — ну вы знаете, это странный котик, который летит бесконечно в космосе, оставляя за собой шлейф из радуги.

Умножать две бесконечности я побоялся. И вам не советую.

Класс Double является оболочкой для данного типа. Без необходимости не используйте в Android класс Double.

Конвертация строки в double

Есть несколько вариантов.

 // если строка null, то будет исключение NullPointerException // если строка содержит неправильные данные, то будет исключение NumberFormatException String s = "435.23"; Double d = Double.valueOf(s); // возвращает не Double, а double (примитивный тип) // выбрасывает аналогичные исключения double x = Double.parseDouble("19.95"); // В Java 9 признан устаревшим. Не используйте и сейчас String s = "135.360"; Double d = new Double(s); // Через DecimalFormat String s = "135.130"; try < DecimalFormat decimalFormat = new DecimalFormat("#"); double d = decimalFormat.parse(s).doubleValue(); System.out.println("Double value for 135.130 is " + d); >catch (ParseException e)

Конвертация double в строку

При работе с числами double следует держать ухо востро. Рассмотрим пример конвертации трёх чисел.

 double number1 = 120; double number2 = 0.033; double number3 = 0.000045158458; System.out.println(String.valueOf(number1)); System.out.println(String.valueOf(number2)); System.out.println(String.valueOf(number3)); /* System.out: 120.0 System.out: 0.033 System.out: 4.5158458E-5 */ 

Первые два числа нормально преобразовались, а вот третье число преобразовалось в строку в странном виде (на самом деле это научное представление числа). И это может источником проблемы при передаче строки куда-нибудь, например, на сервер. Если сервер не ожидает от вас такой подлости, то будет генерировать ошибки из-за странной записи. Нужно найти другие способы конвертации.

Первый способ — используем String.format().

 double number3 = 0.000045158458; System.out.println(String.valueOf(number3)); System.out.println(String.format("%f", number3)); System.out.println(String.format("%.0f", number3)); System.out.println(String.format("%.12f", number3)); /* System.out: 4.5158458E-5 System.out: 0.000045 System.out: 0 System.out: 0.000045158458 */ 

Последний пример самый подходящий для нас, но вам нужно знать, сколько знаков идёт после десятичной точки. Остальные два пригодятся, если число можно округлить.

Второй способ — метод Double.toString(). У меня метод превратил число в «непонятную» строку. А у некоторых этот пример возвращал строку в нормальном виде. Не заслуживает доверия.

 double number3 = 0.000045158458; System.out.println(Double.toString(number3)); /* System.out: 4.5158458E-5 */ 

Третий способ — добавить пустую строку. В Android не помогло, хотя тоже утверждается, что у кого-то выводится в нормальном виде. Врут, наверное.

 double number3 = 0.000045158458; System.out.println(number3 + ""); /* System.out: 4.5158458E-5 */ 

Четвёртый экзотический способ, которым редко пользуются — DecimalFormat.

 double number3 = 0.000045158458; String pattern = "##.############"; DecimalFormat decimalFormat = new DecimalFormat(pattern); System.out.println(decimalFormat.format(number3)); /* System.out: 0.000045158458 */ 

Символы (тип char)

Для хранения символов Java использует специальный тип char. Он отличается от типа char в языках C/C++, где представляет собой целочисленный тип с размером 8 бит. В Java для char используется кодировка Unicode и для хранения Unicode-символов используется 16 бит или 2 байта. Диапазон допустимых значений — от 0 до 65536 (отрицательных значений не существует).

 char ch1, ch2, ch3; ch1 = 67; // код переменной ch2 = 'a'; // сам символ ch3 = 116; // код переменной mInfoTextView.setText("Слово из трёх букв: " + ch1 + ch2 + ch3); 

Из примера выше видно, что переменной можно присвоить код символа или непосредственно сам символ, который следует окружить одинарными кавычками. Попробуйте запустить пример и посмотреть, какое слово получится из трёх указанных символов.

Не следует путать символ ‘a’ со строкой «a», состоящей из одного символа. На экране монитора они выглядят одинаково, но в программах ведут себя по разному.

Стандартные символы ASCII можно выводить сразу. Если нужно вывести специальный символ из Unicode, то можно воспользоваться шестнадцатеричным представлением кода в escape-последовательности — вы указываете обратную наклонную черту и четыре цифры после u. Например:

 char myChar = '\u0054'; 

Хотя тип char используется для хранения Unicode-символов, его можно использовать как целочисленный тип, используя сложение или вычитание.

 char ch1; ch1 = 'x'; mInfoTextView.append("ch1 содержит " + ch1); ch1++; // увеличим на единицу mInfoTextView.append("ch1 содержит " + ch1); 

В результате получим:

 ch1 содержит x ch1 содержит y 

Если вы думаете, что увеличив значение переменной ch1 ещё на одну единицу, получите символ «й», то глубоко заблуждаетесь.

Чтобы узнать, какой символ содержится в значении переменной, заданной как int, можно воспользоваться двумя специальными методами из класса EncodingUtils:

Для стандартных символов ASCII:

 int i = 67; byte[] data = < (byte) i >; CharSequence strSymbol = EncodingUtils.getAsciiString(data); mInfoTextView.setText(strSymbol); 

Для расширенной таблицы символов:

 int i = 379; byte[] data = < (byte) i >; CharSequence strSymbol = EncodingUtils.getString(data, "windows-1251"); mInfoTextView.setText(strSymbol); 

Методы работают со строками, но если мы используем строку из одного символа, то получим то, что нам нужно.

В упрощённом виде, если работаем со стандартными символами ASCII (on 0 до 127), то можно получить символ из int ещё проще.

 int ascii = 65; if(ascii > 127)< System.out.println("Wrong value"); >else

Класс Character

Класс Character является оболочкой вокруг типа char. Чтобы получить значение типа char, содержащее в объекте класса Character, вызовите метод charValue().

С классом Character редко имеют дело в Android, но помните, что класс содержит огромное количество констант и методов. Например, можно определить, является ли символ цифрой или буквой, или написан ли символ в нижнем или в верхнем регистре.

Булевы значения

Тип boolean предназначен для хранения логических значений и может принимать только одно из двух возможных значений: true или false. Данный тип всегда возвращается при использовании операторов сравнения (больше, меньше, равно, больше или равно, меньше или равно, не равно). Также он используется в управляющих операторах if и for.

 boolean check; check = true; 

В отличие от реальной жизни, где вполне может состояться диалог:

- Кать, чай будешь? - Да нет наверное

В компьютерной программе нужно чётко определиться — истина или ложь.

В операторах if используется укороченная запись при значении true:

 if (check == true) . // необязательный вариант if (check) . // укороченная запись 

Java сам поймёт, что переменную check нужно сравнить с true.

Класс Boolean

Класс Boolean является оболочкой вокруг значений типа boolean. Чтобы получить значение типа boolean из объекта класса Boolean, используйте метод booleanValue(). Тип boolean использует 4 байт памяти, а Boolean — 16. Вывод понятен?

Ещё один совет, применимый ко всем типам. Допустим, нам нужно объявить 32 переменных типа boolean:

 boolean mProperty1; boolean mProperty2; . boolean mProperty32; 

Умножаем 4 байта на 32 переменных и получаем 128 байт занятой памяти. А если объявим массив:

 boolean[] mProperty = new boolean[32] 

Считаем: 4 + 8 + 8 + 32 * 1 = 52. С учётом выравнивания памяти по 8 байт, получаем не 52, а 56. Всё равно меньше, чем в первом примере.

Конвертируем строку в булево значение.

 Boolean booleanValue = Boolean.valueOf("true"); System.out.println(booleanValue); 

Конвертируем булево значение в строку.

 boolean boolenValue = true; // первый способ System.out.println(Boolean.toString(booleanValue)); // второй способ System.out.println(String.valueOf(booleanValue)); 

Приведение типов

Когда мы производим какие-то действия с переменными, то нужно следить за типами. Нельзя умножать котов на футбольные мячи, это противоречит здравому смыслу. Также и с переменными. Если вы присваиваете переменной одного типа значение другого типа, то вспоминайте теорию. Например, вы без проблем можете присвоить значение типа int переменной типа long, так как все числа из диапазона типа int гарантировано помещаются в диапазон чисел long. В этом случае Java выполнит преобразование автоматически, вы даже ничего не заметите.

Представим обратную картину — мы хотим присвоить переменной типа byte значение типа double. Java не сможет автоматически выполнить ваше желание. Не все числа типа double могут стать числом типа byte. Но часть чисел может, например, число 9. В таком случае используется так называемое приведение типов, чтобы подсказать Java о допустимости операции.

Итак, автоматическое преобразование типов осуществляется, если оба типа совместимы и длина целевого типа больше длины исходного типа. В этом случае происходит преобразование с расширением. Вы всегда можете преобразовать любое число типа byte в число типа int. Такая операция произойдёт без вашего участия автоматически.

Таблица выглядит следующим образом.

Приведение типов

Сплошные линии обозначают преобразования, выполняемые без потери данных. Штриховые линии говорят о том, что при преобразовании может произойти потеря точности.

Типы целых чисел и чисел с плавающей точкой совместимы частично. Например, число 5 вполне может быть числом с плавающей точкой (5.0).

Совсем не совместимы, например, char и boolean.

С автоматическим приведением мы разобрались. Рассмотрим вариант, когда нужно преобразовать число типа int в число типа byte. Преобразование автоматически невозможно, поскольку byte меньше int. Но, например, число 99 вполне можно использовать и как int и как byte. В этом случае используется явное приведение типов, то есть преобразование из одного типа в другой (преобразование с сужением).

Выглядит это следующим образом:

 int a; byte b; // какие-то операции с переменной b = (byte) a; 

Как видите, вы в скобках указываете тип, к которому нужно явно привести переменную.

Существует ещё вариант приведения с усечением. Это когда число с плавающей точкой приводится к целочисленному типу. В этом случае отбрасывается дробная часть (хвост). Например, число 3.14 будет усечено до числа 3:

 double a = 3.14; byte b = (byte) a; 

Если размер целочисленной части слишком велик для целочисленного типа, то значение будет уменьшено до результата деления по модулю на диапазон целевого типа.

Например, попробуйте преобразовать число 454.874 в тип byte:

 byte b; double d = 454.874; b = (byte) d; infoTextView.append("b равно " + b); 

У меня вывелся удивительный результат: b равно -58.

Рассмотрим такой пример. Допустим у нас есть выражение, где промежуточное значение может выходить за пределы допустимого диапазона:

 byte a = 44; byte b = 55; byte c = 101; int d = a * b - c; 

При умножении переменных a * b промежуточный результат вышел за пределы диапазона допустимых значений для типов byte. Java во время вычисления промежуточных результатов автоматически повышает тип каждого операнда до int и ошибки не происходит.

Это удобно, но может поставить в тупик в следующем примере:

 byte b = 50; b = b * 2; 

С виду всё правильно. Если не слишком больше число типа byte, а итоговый результат тоже не выходит за диапазон допустимых значений. Но Java не позволит вам написать подобный код. Происходит следующее. Во время вычисления выражения тип операндов был автоматически повышен до int, как об этом говорилось выше. При этом тип результата тоже был повышен до int. Получается, что результат вычисления равен типу int, а мы пытаемся его присвоить переменной b, которая у нас объявлена как byte. И это несмотря на то, что итоговый результат может быть типом byte. Как же выйти из этого положения? Следует использовать явное приведение типов:

 byte b = 50; b = (byte) (b * 2); 

Мы рассмотрели единичные примеры. Пора обобщить и запомнить несколько правил.

Типы всех значений byte, short, char повышаются до типа int, как это было рассмотрено выше.

Если один операнд имеет тип long, то тип всего выражения повышается до long.

Если один операнд имеет тип float, то тип всего выражения повышается до float.

Если один операнд имеет тип double, то тип всего выражения повышается до double.

 byte b = 45; char c = 'c'; short s = 1005; int i = 700000; float f = 4.55f; double d = 1.456; double result = (f * b) + (i / c) - (d * s); mInfoTextView.append("d равно " + d); 

В первом промежуточном выражении (f * b) тип переменной b повышается до float и промежуточный результат также становится float. В следующем выражении (i / c) тип у переменной c повышается до int и промежуточный результат также становится типом int. В выражении (d * s) тип переменной s повышается до double и промежуточное выражение также становится double. В результате у нас появились три промежуточные значения типов: float, int, double. При сложении float и int мы получаем float, затем при вычитании с использованием float и double тип повышается до double, который и становится окончательным типом результата выражения.

Long java сколько цифр

Одной из основных особенностей Java является то, что данный язык является строго типизированным. А это значит, что каждая переменная и константа представляет определенный тип и данный тип строго определен. Тип данных определяет диапазон значений, которые может хранить переменная или константа.

Итак, рассмотрим систему встроенных базовых типов данных, которая используется для создания переменных в Java. А она представлена следующими типами.

    boolean : хранит значение true или false

boolean isActive = false; boolean isAlive = true;
byte a = 3; byte b = 8;
short a = 3; short b = 8;
int a = 4; int b = 9;
long a = 5; long b = 10;
double x = 8.5; double y = 2.7;
float x = 8.5F; float y = 2.7F;

При этом переменная может принимать только те значения, которые соответствуют ее типу. Если переменная представляет целочисленный тип, то она не может хранить дробные числа.

Целые числа

Все целочисленные литералы, например, числа 10, 4, -5, воспринимаются как значения типа int , однако мы можем присваивать целочисленные литералы другим целочисленным типам: byte , long , short . В этом случае Java автоматически осуществляет соответствующие преобразования:

byte a = 1; short b = 2; long c = 2121;

Однако если мы захотим присвоить переменной типа long очень большое число, которое выходит за пределы допустимых значений для типа int, то мы столкнемся с ошибкой во время компиляции:

long num = 2147483649;

Здесь число 2147483649 является допустимым для типа long, но выходит за предельные значения для типа int. И так как все целочисленные значения по умолчанию расцениваются как значения типа int, то компилятор укажет нам на ошибку. Чтобы решить проблему, надо добавить к числу суффикс l или L , который указывает, что число представляет тип long:

long num = 2147483649L;

Как правило, значения для целочисленных переменных задаются в десятичной системе счисления, однако мы можем применять и другие системы счисления. Например:

int num111 = 0x6F; // 16-теричная система, число 111 int num8 = 010; // 8-ричная система, число 8 int num13 = 0b1101; // 2-ичная система, число 13

Для задания шестнадцатеричного значения после символов 0x указывается число в шестнадцатеричном формате. Таким же образом восьмеричное значение указывается после символа 0 , а двоичное значение — после символов 0b .

Также целые числа поддерживают разделение разрядов числа с помощью знака подчеркивания:

int x = 123_456; int y = 234_567__789; System.out.println(x); // 123456 System.out.println(y); // 234567789
Числа с плавающей точкой

При присвоении переменной типа float дробного литерала с плавающей точкой, например, 3.1, 4.5 и т.д., Java автоматически рассматривает этот литерал как значение типа double . И чтобы указать, что данное значение должно рассматриваться как float , нам надо использовать суффикс f:

float fl = 30.6f; double db = 30.6;

И хотя в данном случае обе переменных имеют практически одно значения, но эти значения будут по-разному рассматриваться и будут занимать разное место в памяти.

Символы и строки

В качестве значения переменная символьного типа получает одиночный символ, заключенный в одинарные кавычки: char ch=’e’; . Кроме того, переменной символьного типа также можно присвоить целочисленное значение от 0 до 65535 . В этом случае переменная опять же будет хранить символ, а целочисленное значение будет указывать на номер символа в таблице символов Unicode (UTF-16). Например:

char ch=102; // символ 'f' System.out.println(ch);

Еще одной формой задания символьных переменных является шестнадцатеричная форма: переменная получает значение в шестнадцатеричной форме, которое следует после символов «\u». Например, char ch=’\u0066′; опять же будет хранить символ ‘f’.

Символьные переменные не стоит путать со строковыми, ‘a’ не идентично «a». Строковые переменные представляют объект String , который в отличие от char или int не является примитивным типом в Java:

String hello = "Hello. "; System.out.println(hello);

Кроме собственно символов, которые представляют буквы, цифры, знаки препинания, прочие символы, есть специальные наборы символов, которые называют управляющими последовательностями. Например, самая популярная последовательность — «\n». Она выполняет перенос на следующую строку. Например:

String text = "Hello \nworld"; System.out.println(text);

Результат выполнения данного кода:

Hello world

В данном случае последовательность \n будет сигналом, что необходимо сделать перевод на следующую строку.

Начиная с версии 15 Java поддерживает тестовые блоки (text blocks) — многострочный текст, облеченный в тройные кавычки. Рассмотрим, в чем их практическая польза. Например, выведем большой многострочный текст:

String text = "Вот мысль, которой весь я предан,\n"+ "Итог всего, что ум скопил.\n"+ "Лишь тот, кем бой за жизнь изведан,\n"+ "Жизнь и свободу заслужил."; System.out.println(text);

С помощью операции + мы можем присоединить к одному тексту другой, причем продолжение текста может располагаться на следующей строке. Чтобы при выводе текста происходил перенос на следующую строку, применяется последовательность \n.

Результат выполнения данного кода:

Вот мысль, которой весь я предан, Итог всего, что ум скопил. Лишь тот, кем бой за жизнь изведан, Жизнь и свободу заслужил.

Текстовые блоки, которые появились в JDK15, позволяют упростить написание многострочного текста:

String text = """ Вот мысль, которой весь я предан, Итог всего, что ум скопил. Лишь тот, кем бой за жизнь изведан, Жизнь и свободу заслужил. """; System.out.println(text);

Весь текстовый блок оборачивается в тройные кавычки, при этом не надо использовать соединение строк или последовательность \n для их переноса. Результат выполнения программы будет тем же, что и в примере выше.

Типы данных — Основы Java

Внутри высокоуровневых языков программирования данные разделяются по типам. Например, строки относятся к типу String, а числа — к типу int.

Зачем нужны типы? Для защиты программы от трудноотловимых ошибок. Типы определяют две вещи:

  • Допустимые значения. Например, числа в Java делятся на две группы типов: целые int и рациональные float. Такое разделение связано с техническими особенностями работы аппаратуры.
  • Набор допустимых операций. Например, операция умножения имеет смысл для типа «целые числа». Но не имеет смысла для типа «строки»: умножать слово «мама» на слово «блокнот» — бессмыслица.

Язык программирования распознает типы. Поэтому Java не позволит нам умножать строку на строку. Но позволит умножать целое число на другое целое число. Наличие типов и таких ограничений в языке защищает программы от случайных ошибок:

Каким образом Java понимает, что за тип данных перед ним? Любое значение где-то инициализируется. В зависимости от способа инициализации, становится понятно, что именно находится перед нами.

Например, число — это просто число, не обернутое в кавычки или другие парные символы. А вот строки всегда ограничены двойными кавычками. Например, значение «234» считается строкой, хотя внутри нее записаны цифры:

// Компилятор понимает, что тут число var age = 33; 

По-английски строки в программировании называются strings, а строчки текстовых файлов называются lines. Например, в коде выше одна строчка (lines) и ноль строк (strings). В русском языке иногда может быть путаница, поэтому во всех уроках мы будем использовать такие термины:

  • Строка — для обозначения типа данных strings
  • Строчка — для обозначения lines (строчек в текстовых файлах)

Типов данных в Java много, плюс можно создавать свои. Постепенно мы познакомимся со всеми необходимыми и научимся их правильно использовать.

Явная типизация

До сих пор при определении переменных мы использовали ключевое слово var , что может удивить тех, кто имеет какой-то опыт на Java. Обычно определение переменных показывают так:

int x = 3; String greeting = "Hello Hexlet!"; // Error: incompatible types: java.lang.String cannot be converted to int int ops = "test"; 

Пришло время раскрыть карты! Java — это статически типизированный язык. В таких языках тип переменной фиксируется при ее объявлении. В большинстве языков для этого перед именем переменной указывается ее тип — в примере выше это число (int) и строка (String).

Раньше на Java создавали переменные только так, до тех пор пока не появился var . var – специальное ключевое слово, которое включает механизм вывода типов. Вывод типов автоматически определяет тип присваиваемого значения и связывает его с переменной. В примерах выше очевидно, где какой тип, тогда зачем его явно прописывать?

Вывод типов в Java появился в 2018 году, но в некоторых других языках он существует не один десяток лет. Первый язык с выводом типов называется ML и появился он аж в 1973 году. С тех пор вывод типов был добавлен в Ocaml, Haskell, C#, F#, Kotlin, Scala и множество других языков.

Вывод типов предпочтителен в большинстве ситуаций, однако бывает такое, что выводимый тип нас не устраивает. Тогда мы можем указать тип явно.

Какие бывают типы

В этом уроке мы рассмотрим систему типов в Java с высоты птичьего полета, не погружаясь в детали. Но сначала ответим на вопрос, зачем вообще про них знать?

В коде мы все время оперируем данными. Эти данные имеют разную природу, могут быть по-разному организованы, что влияет на удобство работы с ними. Типы преследуют нас на каждом шагу, поэтому без них программирование на Java возможно только на очень базовом уровне.

С другой стороны, не пытайтесь запомнить всю эту информацию про типы наизусть — она дается лишь для общего представления. Все важное о типах вы и так выучите в процессе программирования. Глобально, типы данных в Java делятся на две большие группы:

  • Примитивные — предопределены в Java
  • Ссылочные или не примитивные — создаются самим программистом, за исключением String и Array

У этих групп есть различия, которые мы разберем позже, когда познакомимся с null и объектно-ориентированным программированием. Пока достаточно знать, что имена примитивных типов начинаются с нижнего регистра ( int ), а ссылочных с верхнего ( String ).

Всего в Java восемь примитивных типов данных:

Рассмотрим первые четыре типа. Это целые числа разного размера:

  • byte — занимает в памяти 1 байт, значит может хранить числа от -128 до 127
  • short — занимает в памяти 2 байта
  • int — занимает в памяти 4 байта
  • long — занимает в памяти 8 байт

Посмотрим на примере такого кода:

byte x = 3; // Отработает без проблем // Error: incompatible types: possible lossy conversion from int to byte byte y = 270; 

Определение переменной y завершилось с ошибкой, потому что мы указали тип byte, но присвоили переменной значение 270, которое выходит за множество допустимых значений.

Возникает закономерный вопрос. Зачем аж четыре типа для хранения чисел? Почему бы не сделать один, в который влезает почти любое большое число?

Технически так сделать можно, но мы находимся в мире инженерных решений. У любого решения всегда есть обратная сторона, поэтому невозможно сделать идеально — придется чем-то пожертвовать. В данном случае, объемом занимаемой памяти. Если оставить только long, то программа, активно оперирующая числами, начнет занимать слишком много места в оперативной памяти, что может быть критично.

Такая же логика использовалась для типов float и double. Они оба отвечают за рациональные числа. Разница лишь в том, что double — это двойной float, то есть в памяти он занимает в два раза больше места.

Создатели Java полагаются на разумность программистов, на их способность правильно подобрать нужные типы в зависимости от задачи. Для каких-то экстремальных приложений так и происходит, но в типичной разработке все просто. Программисты выбирают int для целых чисел и double для рациональных.

Рассмотрим оставшиеся типы данных.

Тип boolean отвечает за логические значения true и false . Им посвящен целый раздел, там мы про него и поговорим.

Особняком стоит тип char — символ. Это не строка, у него другой способ определения — через одиночные кавычки:

char ch = 'a'; // Error: incompatible types: java.lang.String cannot be converted to char char ch2 = "b"; 

Строка, состоящая из одного символа — это не символ. Кажется, нелогично, но с точки зрения типов все так и должно быть, со временем вы это прочувствуете.

Извлечение символа из строки извлекает как раз символ, а не строку, состоящую из одного символа:

"hexlet".charAt(1); // 'e' 

Хорошо, а где тип данных String — строка? Дело в том, что она не является примитивным типом. Внутри она представляет собой массив символов. Несмотря на это техническое различие, строки используются наравне с примитивными типами без особых отличий.

Значение по умолчанию

Примитивные данные всегда имеют значение, даже если они определяются без инициализации:

int a; System.out.println(a); // => 0 

У каждого примитивного типа есть свое значение по умолчанию:

Значение null

Особняком в Java стоит значение null . В Java оно не является типом. Это просто конкретное значение со специальным смыслом и логикой работы. Начнем с примера:

// Определение переменной без инициализации значением // С var такое не сработает, так как невозможно вывести тип String a; 

Что находится внутри переменной a ? Если мы ее распечатаем, то увидим null . Значение null используется для ссылочных типов, когда значение не определено.

Как такое возможно? Представьте, что мы хотим извлечь из базы данных пользователя, а его там нет. Что вернет нам запрос в базу? Вот именно для таких ситуаций и нужен null .

Их гораздо больше, чем может показаться на первый взгляд. Чем дальше мы будем двигаться, тем чаще он начнет встречаться:

var user = // тут делаем запрос в базу // Если данных нет, то user станет null // Запись выше равносильна var user = null; 

Из вышесказанного следует важный вывод. Любой ссылочный тип данных может принимать значение null . То есть, null является значением любого ссылочного типа. А вот примитивные типы и null не совместимы. Примитивное значение всегда должно быть определено:

// Error: incompatible types: cannot be converted to int int x = null; 

Явное преобразование типов

В программировании регулярно встречаются задачи, когда один тип данных нужно преобразовать в другой. Простейший пример – работа с формами на сайтах.

Данные формы всегда приходят в текстовом виде, даже если значение число. Вот как его можно преобразовать:

// станет int var number = Integer.parseInt("345"); System.out.println(number); // => 345 

Если нужно конвертировать из примитивного типа в примитивный, то все проще. Достаточно перед значением в скобках указать желаемый тип. В результате значение справа преобразуется в значение другого типа, указанного слева:

var result = (int) 5.1; System.out.println(result); // => 5 

Преобразование типов можно использовать внутри составных выражений:

// Дополнительные скобки помогают визуально отделить части выражения друг от друга var result = 10 + ((int) 5.1); System.out.println(result); // => 15 

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Об обучении на Хекслете

  • Статья «Как учиться и справляться с негативными мыслями»
  • Статья «Ловушки обучения»
  • Статья «Сложные простые задачи по программированию»
  • Урок «Как эффективно учиться на Хекслете»
  • Вебинар « Как самостоятельно учиться »

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *