Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Типы данных Java: Основы программирования

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

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

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

"one" * "two"
Error:
bad operand types for binary operator '*'
    first type:  java.lang.String
    second type: java.lang.String

Каким образом Java понимает, что за тип данных перед ним? Достаточно просто. Любое значение где-то инициализируется и, в зависимости от способа инициализации, становится понятно, что перед нами. Например, число это просто число не обернутое в парные символы, например, кавычки. А вот строки всегда ограничены двойными кавычками. Например, такое значение "234" – строка, несмотря на то, что внутри нее записаны цифры.

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

По-английски строки в программировании называются "strings", а строчки текстовых файлов называются "lines". Например, в коде выше одна строчка (lines), и нет никаких строк (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 8 примитивных типов данных: byte, short, int, long, float, double, boolean and char. Первые 4 это целые числа разного размера. Например byte занимает в памяти, как ни трудно догадаться, один байт, а значит может хранить числа от -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, которое выходит за множество возможных значений.

Возникает закономерный вопрос. Зачем аж 4 типа для хранения чисел? Почему бы не сделать один, в который влезает почти любое большое число? Технически так сделать можно, но мы находимся в мире инженерных решений. Это значит, что у любого решения всегда есть обратная сторона, поэтому невозможно сделать идеально, придется чем-то пожертвовать. В данном случае, объемом занимаемой памяти. Если оставить только 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 спросите вы? String не является примитивным типом. Внутри она представляет из себя массив символов. Несмотря на это техническое различие, строки используются наравне с примитивными типами без особых отличий.

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

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

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

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

byte    0
short   0
int     0
long    0
float   0.0
double  0.0
char    ''
boolean false

Значение null

Особняком в Java стоит значение null. Здесь оно, в отличии от других языков программирования, не является типом, это просто конкретное значение со специальным смыслом и логикой работы. Начнем с примера:

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

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

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

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

// Error: incompatible types: <nulltype> 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

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

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

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

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

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

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

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

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

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

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

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Java-разработчик
Профессия
Разработка приложений на языке Java
25 мая 10 месяцев

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»