Арифметические и математические операторы java с примерами
Содержание:
- Математика
- Пример 2: Арифметические операторы
- Битовые сдвиги в Java
- Операции сравнения
- Основные математические функции
- Побитовые (поразрядные) операции
- Унарные операции
- Преимущества Java-программирования
- Что такое функциональный интерфейс
- Тип char
- Как создать класс в Java
- Java Integer Math
- JSON
- Non-Primitive Data Types
- Как логические операторы работают с целыми числами
- Вещественные типы
- Оператор continue
- Оператор switch
Математика
Float или Double?
Программисты часто не могут выбрать необходимую точность для чисел с плавающей запятой. Float требует всего 4 байта, но имеет только 7 значащих цифр, а Double в два раза точнее (15 цифр), но в два раза прожорливее.
Фактически, большинство процессоров могут одинаково эффективно работать как с Float, так и с Double, поэтому воспользуйтесь рекомендацией Бьорна Страуструпа (автор языка С++):
Проверка на нечетность
Можно ли использовать этот код для точного определения нечетного числа?
Надеюсь, вы заметили хитрость. Если мы решим таким образом проверить отрицательное нечетное число (например, -5), остаток от деления не будет равен единице, поэтому воспользуйтесь более точным методом:
Он не только решает проблему отрицательных чисел, но и работает более производительно, чем предыдущий метод. Арифметические и логические операции выполняются намного быстрее, чем умножение и деление.
Пример 2: Арифметические операторы
class ArithmeticOperator { public static void main(String[] args) { double number1 = 12.5, number2 = 3.5, result; // Используется оператор сложения result = number1 + number2; System.out.println("number1 + number2 = " + result); // Используется оператор вычитания result = number1 - number2; System.out.println("number1 - number2 = " + result); // Используется оператор умножения result = number1 * number2; System.out.println("number1 * number2 = " + result); // Используется оператор деления result = number1 / number2; System.out.println("number1 / number2 = " + result); // Используется оператор остатка result = number1 % number2; System.out.println("number1 % number2 = " + result); } }
Когда вы запустите программу, на экран выведется:
number1 + number2 = 16.0 number1 - number2 = 9.0 number1 * number2 = 43.75 number1 / number2 = 3.5714285714285716 number1 % number2 = 2.0
В примере с оператором деления Java, приведенном выше, использованные операнды – переменные. Кроме этого могут использоваться символьные значения. Например:
result = number1 + 5.2; result = 2.3 + 4.5; number2 = number1 -2.9;
Оператор «+» также может быть использован, чтобы соединить (конкатенировать) две строки или больше.
Битовые сдвиги в Java
Операция
Описание
>>
Сдвиг вправо (арифметический сдвиг)
>>>
Сдвиг вправо с заполнением нулями (беззнаковый сдвиг)
<<
Сдвиг влево
Битовые сдвиги смещают все двоичные разряды значения на указанное количество позиций.
Общая форма:
Например:
Для того чтобы понять, как происходит сдвиг, лучше рассмотреть его на примере двоичных чисел:
При сдвиге отрицательных чисел имеется разница в использовании операторов и . Операция распространяет знаковый (левый) бит направо до конца, заполняет нулями. У положительных чисел результат будет одинаков.
Типы и продвигаются к типу при вычислении выражения.
Пример битовых сдвигов:
Операции сравнения
Операции сравнения позволяют проверить, больше ли один операнд другого, либо что один операнд равен другому и т. д.
Вот список операций сравнения в Java:
== равенство (обратите внимание, что нужно использовать два символа равно для сравнения, а не один)
!= неравенство
> больше
>= больше или равно
Все операции сравнения возвращают логическое значение
boolean, что означает, что результат операции сравнения можно присвоить переменной этого типа и использовать в любом месте, где требуется значение типа
boolean.
Пример:
class Main {
public static void main(String[] args) {
int x = 3;
double d = 3.1;
System.out.println(x == d); // false
System.out.println(x > d); // false
System.out.println(x < d); // true
}
}
1 |
classMain{ publicstaticvoidmain(Stringargs){ intx=3; doubled=3.1; System.out.println(x==d);// false System.out.println(x>d);// false System.out.println(x<d);// true } } |
При сравнении используются следующие правила:
- Если один из операндов
NaN, то результат
false. -
-Infinity меньше
+Infinity - -0.0 с плавающей точкой равен +0.0 с плавающей точкой
- При сравнении примитивов разных типов значение меньшего типа преобразуется в больший тип.
Основные математические функции
Java.lang.Math содержит набор базовых математических функций для получения абсолютного значения, наибольшего и наименьшего из двух значений, округления значений, случайных значений и т. д.
Math.abs()
Функция Math.abs() возвращает абсолютное положительное значение переданного ей параметра. Если значение параметра является отрицательным, знак “-” удаляется и возвращается положительное значение, соответствующее отрицательному значению без знака. Вот два примера:
int abs1 = Math.abs(10); // abs1 = 10 int abs2 = Math.abs(-20); // abs2 = 20
Абсолютное значение 10 равно 10. Абсолютное значение -20 равно 20.
Метод Math.abs() представлен в 4 версиях:
Math.abs(int) Math.abs(long) Math.abs(float) Math.abs(double)
Какой из этих методов вызывается, зависит от типа параметра, передаваемого методу Math.abs().
Math.ceil()
Функция округляет значение с плавающей запятой до ближайшего целого числа. Округленное значение возвращается как двойное. Вот пример:
double ceil = Math.ceil(7.343); // ceil = 8.0
После выполнения этого Java-кода переменная ceil будет содержать значение 8.0.
Math.floor()
Функция Math.floor() округляет значение с плавающей запятой до ближайшего целочисленного значения. Округленное значение возвращается как двойное. Вот пример:
double floor = Math.floor(7.343); // floor = 7.0
После выполнения ceil будет содержать значение 8.0.
Math.floorDiv()
Метод Math.floorDiv() делит одно целое число (int или long) на другое и округляет результат до ближайшего целочисленного значения. Если результат положительный, эффект такой же, как при использовании оператора “/” (деления), описанного ранее в этом тексте.
Однако, если результат отрицательный, результат не тот же. С помощью оператора “/” дроби просто усекаются. Для положительных чисел это соответствует округлению в меньшую сторону, для отрицательных – в большую. Метод floorDiv() округляет до ближайшего отрицательного целого числа, вместо того, которое будет происходить при усечении дроби.
Вот пример:
double result3 = Math.floorDiv(-100,9); System.out.println("result3: " + result3); double result4 = -100 / 9; System.out.println("result4: " + result4);
Выходные данные:
result3: -12.0 result4: -11.0
Это показывает разницу между оператором “/” и Math.floorDiv().
Math.min()
Метод Math.min() возвращает наименьшее из двух значений, переданных ему в качестве параметра:
int min = Math.min(10, 20);
После выполнения этого кода переменная min будет содержать значение 10.
Math.max()
Метод Math.max() возвращает наибольшее из двух значений, переданных ему в качестве параметра:
int max = Math.max(10, 20);
После выполнения этого кода переменная max будет содержать значение 20.
Побитовые (поразрядные) операции
В следующей таблице представлены побитовые операции применяемые в языке Java:
Операция
Описание
~
Поразрядная унарная операция НЕ (дополнение)
&
Поразрядная логическая операция И (AND, побитовая конъюнкция)
|
Поразрядная логическая операция ИЛИ (OR, побитовая дизъюнкция)
^
Поразрядная логическая операция исключающее ИЛИ (XOR)
Побитовые операторы применяются к целочисленным типам , , , , . Побитовые операторы применяются к каждому отдельному биту каждого операнда.
Результаты выполнения побитовых логических операций:
A |
B |
A | B |
A & B |
A ^ B |
~A |
1 |
|||||
1 |
1 |
1 |
|||
1 |
1 |
1 |
1 |
||
1 |
1 |
1 |
1 |
1.1. Побитовое ИЛИ (OR , |)
Результирующий бит, полученный в результате выполнения оператора OR, равен 1, если соответствующий бит в любом из операндов равен 1.
1.2. Побитовое И (AND , &)
Значение бита, полученное в результате выполнения побитового оператора AND, &, равно 1, если соответствующие биты в операндах также равны 1. Во всех остальных случаях значение результирующего бита равно 0.
1.3. Побитовое исключающее ИЛИ (XOR , ^)
Результирующий бит, полученный в результате выполнения оператора XOR, ^, равен 1, если соответствующий бит только в одном из операндов равен 1. Во всех других случаях результирующий бит равен 0.
1.4. Побитовое НЕ (NOT , ~)
Унарный оператор NOT (Не), ~, называемый также побитовым дополнением, инвертирует все биты операнда.
Рассмотрим теперь применение побитовых операций в программе. В следующем примере также показано применение метода , который приводит десятичное значение к двоичному:
Унарные операции
Унарными называются операции, которые имеют только один операнд. Унарные операции бывают префиксные и постфиксные.
Постфиксные унарные операции ставятся после операнда:
- Инкремент (увеличение на 1)
++ - Декремент (уменьшение на 1)
—
Примеры:
Java
int x = 3;
short y = 100;
x++; // после выполнения x становится равным 4.
y—; // после выполнения y становится равным 99.
1 |
intx=3; shorty=100; x++;// после выполнения x становится равным 4. y—;// после выполнения y становится равным 99. |
Префиксные унарные операции ставятся перед операндом:
- Унарный плюс (обозначает положительные числа, хотя числа положительными будут и без него)
+ - Унарный минус (обозначает отрицательные числа)
— - Логическое НЕ (инвертирует значение логического типа, превращая
true в
false и наоборот)
! - Префиксный инкремент (увеличивает значение на 1)
++ - Префиксный декремент (уменьшает значение на 1)
—
Примеры:
Java
int x1 = +10; // положительная десятка
int x2 = -x1; // -10
boolean b1 = true
boolean b2 = !b1; // false
++x1; // теперь x1 равен 11.
—x2; // теперь x2 равен -11
1 |
intx1=+10;// положительная десятка intx2=-x1;// -10 booleanb1=true booleanb2=!b1;// false ++x1;// теперь x1 равен 11. —x2;// теперь x2 равен -11 |
Отличие постфиксного и префиксного инкремента и декремента
С виду может показаться, что префиксный и постфиксные инкремент и декремент одинаковы, но это не так. Их отличие в том, что префиксный инкремент и декремент возвращают значение, которое получилось после операции увеличения и уменьшения соответственно, а постфиксный инкремент и декремент возвращают исходное значение, которое было до увеличения или уменьшения.
Пример:
Main.java
Java
class Main {
public static void main(String[] args) {
int x1 = 100;
int x2 = 145;
int y1 = ++x1;
int y2 = —x2;
// Вывод для префиксных операций
System.out.println(«\nPrefix ++, — test»);
System.out.println(«x1=» + x1 + «; y1=» + y1);
System.out.println(«x2=» + x2 + «; y2=» + y2);
// Возвращаем исходные значения
x1 = 100;
x2 = 145;
int z1 = x1—;
int z2 = x2++;
// Вывод для постфиксных операций
System.out.println(«\nPostfix ++, — test»);
System.out.println(«x1=» + x1 + «; z1=» + z1);
System.out.println(«x2=» + x2 + «; z2=» + z2);
}
}
1 |
classMain{ publicstaticvoidmain(Stringargs){ intx1=100; intx2=145; inty1=++x1; inty2=—x2; // Вывод для префиксных операций System.out.println(«\nPrefix ++, — test»); System.out.println(«x1=»+x1+»; y1=»+y1); System.out.println(«x2=»+x2+»; y2=»+y2); // Возвращаем исходные значения x1=100; x2=145; intz1=x1—; intz2=x2++; // Вывод для постфиксных операций System.out.println(«\nPostfix ++, — test»); System.out.println(«x1=»+x1+»; z1=»+z1); System.out.println(«x2=»+x2+»; z2=»+z2); } } |
Не помню, описывал ли я это, но две косые черты
// означают комментарий. Компилятор игнорирует любой текст, находящийся правее
//, что позволяет записать какое-нибудь пояснение для будущего читателя программы. Строки
System.out.println выводят текст в консоль.
Этот пример выводит в консоль следующее:
Prefix ++, — test
x1=101; y1=101
x2=144; y2=144
Postfix ++, — test
x1=99; z1=100
x2=146; z2=145
1 |
Prefix ++, — test x1=101; y1=101 x2=144; y2=144 Postfix ++, — test x1=99; z1=100 x2=146; z2=145 |
Как видно из примера
y1 и
y2 стали равны значениям
x1 и
x2, которые получились после осуществления операций инкремента и декремента соответственно, а
z1 и
z2 стали равны значениям
x1 и
x2, которые были до операций инкремента и декремента.
Преимущества Java-программирования
Независимость от архитектуры и платформы. Вы пишете код, не задумываясь об особенностях операционной системы или процессора. Всё это берёт на себя виртуальная машина, а вы только пишете логику работы.
Объектно-ориентированное программирование. ООП — это современный стандарт программирования в коммерческих и промышленных системах. В случае с Java это получится само собой: дело в том, что, как и Ruby, Java — чистый ООП-язык. В нём даже функции превратились в методы и могут существовать только внутри класса.
Работа с памятью. Программисту не нужно следить за тем, сколько памяти расходует его программа и как её освободить, когда какая-то переменная больше не нужна. Для этого в Java встроено автоматическое управление памятью: Java не допускает её утечек и разрастания объёма, а после завершения программы освобождает все ресурсы.
Безопасность. Виртуальная машина сама следит за тем, чтобы программа не получила доступ к тому, что выходит за её полномочия. Например, Java-программа не сможет прочитать содержимое остальной оперативной памяти или связаться с другим компьютером, если это не предусмотрено изначальными правами доступа.
Большое сообщество и поддержка. Java — третий по популярности язык программирования в мире. В Сети есть тысячи сайтов, которые рассказывают об этом языке, помогают разобраться в коде или содержат готовые решения.
Стандарт в корпоративном программировании. Большим компаниям в программах нужна надёжность, стабильность работы и возможность поддерживать их долгое время. Сочетание ООП, управления памятью и независимости от архитектуры делает Java идеальным решением для этого.
Что такое функциональный интерфейс
Функциональный интерфейс — это интерфейс, который содержит ровно один абстрактный метод, то есть описание метода без тела. Статические методы и методы по умолчанию при этом не в счёт, их в функциональном интерфейсе может быть сколько угодно.
Когда параметром метода является функциональный интерфейс, при вызове этого метода одним из аргументов должен быть блок кода.
Передаваемый блок кода должен удовлетворять следующему условию: его сигнатура должна совпадать с сигнатурой единственного абстрактного метода функционального интерфейса.
Звучит непросто, поясним на примере:
Важно. В Java есть несколько готовых функциональных интерфейсов с разным числом и типами входных-выходных параметров
(Как раз из таких ToIntBiFunction выше.) А если мы создаём новый функциональный интерфейс, то важно не забыть аннотацию @FunctionalInterface. Увидев её, компилятор проверит, что интерфейс и правда является функциональным.
Функциональный интерфейс ToIntBiFunction<T, U> подходит к тому примеру, с которого мы начинали. Это значит, что мы можем передать в него аргументом код, который:
- принимает на вход два параметра (T t, U u). T и U указывают на то, что аргументы могут быть разных типов. Например, Long и String. Для нас это даже избыточно, у нас они одного типа — int;
- возвращает значение типа int.
Вот что получится:
Кусочек ToIntBiFunction<Integer, Integer> говорит: передавай сюда метод с такой же сигнатурой, как у метода внутри меня.
Чтобы внутри метода processTwoNumbers выполнить переданный код, нужно вызвать метод из функционального интерфейса:
Вот мы и добрались до лямбда-выражений.
Тип char
Среди примитивных типов в Java есть еще один, который заслуживает особого внимания — тип . Его название происходит от слова Character, а сам тип используется для того, чтобы хранить символы.
А ведь символы — это как раз то, из чего состоят строки: каждая строка содержит в себе массив символов.
Но еще интереснее тот факт, что тип — это и числовой тип тоже! Так сказать, тип двойного назначения.
Все дело в том, что на самом деле тип хранит не символы, а коды символов из кодировки Unicode. Каждому символу соответствует число — числовой код символа.
Каждая переменная типа занимает в памяти два байта (как и тип ). Но в отличие от типа , целочисленный тип — беззнаковый, и может хранить значения от до .
Тип — гибридный тип. Его значения можно интерпретировать и как числа (их можно складывать и умножать), и как символы. Так было сделано потому, что хоть символы и имеют визуальное представление, для компьютера они в первую очередь просто числа. И работать с ними как с числами гораздо удобнее.
Unicode
Unicode — это специальная таблица (кодировка), которая содержит все символы мира. И у каждого символа есть свой номер. Выглядит она примерно так:
Присвоить значение переменной типа можно разными способами.
Код | Описание |
---|---|
Переменная будет содержать латинскую букву . | |
Переменная будет содержать латинскую букву . Ее код как раз . | |
Переменная будет содержать латинскую букву . Ее код как раз , что равно в шестнадцатеричной системе. |
|
Переменная будет содержать латинскую букву . Ее код как раз , что равно в шестнадцатеричной системе. Два лишних нуля ничего не меняют. |
|
Переменная будет содержать латинскую букву . Еще один способ задать символ по его коду. |
Чаще всего просто указывают символ в кавычках (как в первой строке таблицы). Хотя популярен и последний способ. Его преимущество в том, что его можно использовать в строках.
И как мы говорили, тип — это и целочисленный тип тоже, поэтому можно написать так:
Код | Вывод на экран |
---|---|
На экран будет выведена латинская буква . Потому что: – – – |
Работа с типом
Каждый символ — это в первую очередь число (код символа), а потом уже символ. Зная код символа, всегда можно получить его в программе. Пример:
Код | Вывод на экран |
---|---|
Стандартные коды
Вот самые известные коды символов:
Символы | Коды |
---|---|
, , , … | , , , … |
, , , … | , , , … |
, , , … | , , , … |
Как создать класс в Java
Теперь можно приступить к созданию классов. Начнём с пользователя:
Слово public выступает модификатором доступа — он определяет, откуда будет доступен компонент. Для класса можно указать следующие модификаторы:
- public — доступно в любых частях программы (применимо и к другим компонентам);
- default — доступно только классам из того же пакета.
Теперь в основном файле можно создать объект класса User:
Мы указали для объекта user1 класс User, а после оператора присваивания указали ключевое слово new и запустили конструктор (об этом позже). Вот как будет выполнена программа:
Создание объекта называется объявлением экземпляра класса — тут же можно использовать конструктор, чтобы сразу задать значения атрибутам.
Для этого нужно в теле класса создать метод с таким же названием, что и класс. Ему можно передать аргументы, с которыми можно провести операции:
Обратите внимание, что внутри класса атрибуты вызываются с помощью ключевого слова this. Это нужно для того, чтобы компилятор не путался, с какой переменной работать — например, в случае, если у аргумента такое же имя, как и у атрибута:. Теперь, чтобы создать объект, нужно немного поменять код:
Теперь, чтобы создать объект, нужно немного поменять код:
Дальше можно создать класс для работы с сообщениями:
Обратите внимание, что в этот раз для атрибутов from и to мы задали модификатор private, а в качестве типа стоит User. Private позволяет закрыть доступ к элементам извне — то есть их можно менять только внутри методов самого класса
Это позволяет защитить атрибуты от незапланированного доступа. Если же вы хотите получать или менять атрибуты, можно воспользоваться getter и setter. Это специальные методы, которые позволяют обратиться к защищённой переменной:
Теперь можно написать код, который будет создавать сообщение:
Вот как это работает:
Java Integer Math
Математические операции, выполняемые с целочисленными типами Java (byte, short, int и long), ведут себя немного иначе, чем обычные математические операции. Поскольку целочисленные типы не могут содержать дроби, в каждом вычислении с одним или несколькими целочисленными типами все дроби в результате обрезаются. Посмотрите на это математическое выражение:
int result = 100 / 8;
Результат этого деления будет 12,5, но так как два числа являются целыми числами, фракция .5 обрезается. Результат, следовательно, всего 12.
Округление также происходит в подрезультатах больших вычислений.
С плавающей точкой Math
Java содержит два типа данных с плавающей точкой: float и double. Они могут содержать дроби в числах. Если нужны дробные выражения в математических выражениях, вы должны использовать один из этих типов данных. Вот пример математического выражения с плавающей точкой:
double result = 100 / 8;
Несмотря на то, что переменная результата теперь имеет тип с плавающей запятой (double), конечный результат по-прежнему равен 12 вместо 12,5. Причина в том, что оба значения в математическом выражении (100 и 8) оба являются целыми числами. Таким образом, результат деления одного на другое сначала преобразуется в целое число (12), а затем присваивается переменной результата.
Чтобы избежать округления вычислений, необходимо убедиться, что все типы данных, включенные в математическое выражение, являются типами с плавающей запятой. Например, вы могли бы сначала присвоить значения переменным с плавающей запятой следующим образом:
double no1 = 100; double no2 = 8; double result = no1 / no2;
Теперь переменная результата будет иметь значение 12,5.
В Java есть способ заставить все числа в расчете быть переменными с плавающей точкой. Вы ставите числа с большой буквы F или D. Вот пример:
double result = 100D / 8D;
Обратите внимание на прописные буквы D после каждого числа. Этот верхний регистр D говорит Java, что эти числа должны интерпретироваться как числа с плавающей запятой, и, таким образом, деление должно быть делением с плавающей запятой, которое сохраняет дроби вместо их обрезания
На самом деле вы также можете сделать число длинным, добавив суффикс числа к верхнему регистру L, но long по-прежнему является целочисленным типом, поэтому он не будет сохранять дробные части в вычислениях.
Точность с плавающей точкой
Типы данных с плавающей точкой не являются точными на 100%. Вы можете столкнуться с ситуациями, когда числа со многими дробями не складываются с ожидаемым числом. Если вычисление с плавающей запятой приводит к числу с большим количеством дробей, чем может обработать число с плавающей запятой или двойное число, дроби могут быть обрезаны. Конечно, заданная точность может быть более чем достаточной для многих типов вычислений, но имейте в виду, что дроби могут фактически быть отсечены.
Посмотрите:
double resultDbl3 = 0D; System.out.println("resultDbl3 = " + resultDbl3); for(int i=0; i<100; i++){ resultDbl3 += 0.01D; } System.out.println("resultDbl3 = " + resultDbl3);
Вывод выводится при выполнении этого кода с Java 8:
resultDbl3 = 0.0 resultDbl3 = 1.0000000000000007
Первый оператор System.out.println() правильно печатает значение 0.0, которое является начальным значением переменной resultDbl3.
Однако второй оператор System.out.println() выводит несколько странный результат. Добавление значения 0,01 к 0 всего 100 раз должно привести к значению 1,0, верно? Но каким-то образом окончательный результат 1.0000000000000007. Как видите, что-то не так во фракциях.
Обычно неточность с плавающей запятой незначительна, но все же важно знать об этом
JSON
Сериализация и Десериализация
JSON — невероятно удобный и полезный синтаксис для хранения и обмена данными. Java полностью поддерживает это.
Прим. перев. Для использования JSON из примера необходимо подключить библиотеку JSON Simple.
Вы можете сериализовать данные следующим образом:
Получается следующая строка JSON:
Десериализация в Java выглядит так:
Используемый в примере файл JSON (jsonDemoFile.json):
Прим. перев. В Java проектах очень часто для работы с JSON используют библиотеки Gson от Google или Jackson. Обе библиотеки очень популярны и хорошо поддерживаются. Попробуйте и их.
Non-Primitive Data Types
Non-primitive data types are called reference types because
they refer to objects.
The main difference between primitive and non-primitive data types are:
- Primitive types are predefined (already defined) in Java. Non-primitive types are created by the programmer and
is not defined by Java (except for ). - Non-primitive types can be used to call methods to perform certain operations, while primitive types cannot.
- A primitive type has always a value, while non-primitive types can be .
- A primitive type starts with a lowercase letter, while non-primitive types starts with an uppercase letter.
- The size of a primitive type depends on the data type, while non-primitive types have all the same size.
Examples of non-primitive types are Strings, Arrays, Classes, Interface, etc. You will learn more about these in a later chapter.
❮ Previous
Next ❯
Как логические операторы работают с целыми числами
Мы уже знаем, что логические операции применимы к логическим аргументам (операндам). Каждый логический операнд — это выражение, которое является истинным (true) или ложным (false) — то есть возвращает булево значение. Иными словами, логический операнд — это выражение типа boolean.
Выходит, применять логические операторы к целочисленным аргументам нельзя?
Можно. Внутри Java все целочисленные типы представлены двоичными числами разной длины. И к ним уже применимы бинарные логические операторы ^, | и &.
Только в этом случае они работают с двоичным представлением операндов — выполняют операции над их битами попарно (рассматривая их как логические единицы и нули). Поэтому и сами операторы ^, | и & зовутся побитовыми.
Как ^, | и & работают с целочисленными операндами
Рассмотрим пример:
Чтобы повторить вычисления Java, нужно:
- Перевести значения обоих операндов в двоичную систему счисления.
- Расположить результаты перевода друг под другом.
- Сравнять в них число разрядов (дополнить лидирующими нулями).
- Применить к битам из каждого столбца оператор (&, | или ^).
- Записать результат каждой операции ниже в том же столбце.
- Перевести итог в десятичную форму.
Потренируемся: вычислим сами 3 & 5
Число 3 в двоичной системе счисления имеет вид 11, а число 5 — 101.
Так как у числа 5 три разряда в двоичной системе, а у числа 3 — всего два, добавим лидирующий ноль к числу 3 в двоичной системе и получим 011.
Берём цифры из обоих чисел и применяем к ним попарно оператор & (AND):
3(10) = 011(2) | 1 | 1 | |
& | & | & | |
5(10) = 101(2) | 1 | 1 | |
= | = | = | |
001(2) = 1(10) | 1 |
Вещественные типы
Среди примитивных типов также есть два вещественных. Хотя это не совсем точное название. Официально они называются числа с плавающей точкой — floating point numbers. Название происходит из стандарта, когда целую и дробную часть числа разделяет точка (а не запятая).
Полезно:
В каждой стране свои стандарты для записи чисел (внезапно!).
Многие из нас привыкли писать точки для разделения тысяч и запятую для отделения дробной части: например, мы бы записали так . А вот в США, где жили создатели Java, принят другой стандарт:
В Java есть два примитивных типа с плавающей точкой: и .
Как мы уже говорили ранее, эти типы внутри устроены специфическим образом: фактически внутри каждой переменной этих типов находится не одно число, а два:
Например, дробное число можно представить как . Поэтому в памяти оно будет представлено как два числа (мантисса — значащая часть числа) и (экспонента — степень десятки)
Тип
Само название типа происходит от floating point number. Размер этого типа совсем небольшой — всего 4 байта (32 бита), но он может хранить значения от до . Под мантиссу отдается 24 бита, под экспоненту — 8 бит. Этот тип способен хранить всего 8 значащих цифр.
Такой подход позволяет хранить гораздо большие числа, чем , используя все те же 4 байта. Но при этом мы жертвуем точностью. Часть памяти расходуется на хранение мантиссы, поэтому такие числа хранят всего 6-7 знаков после запятой, остальные отбрасываются.
Пример:
Код | Значение переменной |
---|---|
Как видите, основной недостаток этого типа — очень маленькое количество значащих цифр и потеря точности уже в восьмой цифре. Поэтому тип не сильно популярен среди Java-программистов.
Тип
Тип является стандартным типом с плавающей точкой. Его название происходит от double floating point. Его еще называют числом с плавающей точкой двойной точности. Все вещественные литералы по умолчанию имеют тип .
Этот тип занимает 8 байт памяти (64 бита) и может хранить значения от до . Важным моментом является то, что под его мантиссу отводится 53 бита, а остальные 11 – под экспоненту.
Это позволяет хранить 15-17 значащих цифр.
Пример:
Код | Значение переменной |
---|---|
Такая точность, особенно в сравнении с типом , является определяющей: 99% всех операций с вещественными числами выполняются с типом .
Под экспоненту выделяется бит, что позволяет хранить степень десятки от до (степень двойки — от до ). Тип легко может хранить число с сотней нулей после запятой:
Код | Значение переменной |
---|---|
Оператор continue
Оператор
continue позволяет пропустить текущую итерацию и перейти сразу к следующей итерации цикла
for ,
while или
do-while. Он тоже бывает с меткой и без метки.
Пример без метки:
Java
for (int n = 0; n <= 10; n++) {
if (n % 2 == 0) continue;
System.out.println(n);
}
1 |
for(intn=;n<=10;n++){ if(n%2==)continue; System.out.println(n); } |
Выведет в консоль:
1
3
5
7
9
1 |
1 3 5 7 9 |
Пример с меткой:
Java
// …
outer_label:
for (int n = 4; n <= 9; n++) {
int m = 3;
while (m <= 5) {
// Если остаток от деления n на m равен 0,
// то переходим к следующей итерации
// цикла outer_label
if (n % m == 0) continue outer_label;
System.out.println(«n=» + n + «; m=» + m);
m++;
}
}
1 |
// … outer_label for(intn=4;n<=9;n++){ intm=3; while(m<=5){ // Если остаток от деления n на m равен 0, // то переходим к следующей итерации // цикла outer_label if(n%m==)continueouter_label; System.out.println(«n=»+n+»; m=»+m); m++; } } |
Это выведет в консоль:
n=4; m=3
n=5; m=3
n=5; m=4
n=7; m=3
n=7; m=4
n=7; m=5
n=8; m=3
1 |
n=4; m=3 n=5; m=3 n=5; m=4 n=7; m=3 n=7; m=4 n=7; m=5 n=8; m=3 |
Оператор switch
Рассмотрим следующий кусок кода:
Java
if (mode == 0) {
// operators for mode 0
} else if (mode == 1) {
// operators for mode 1
} else if (mode == 2) {
// operators for mode 2
} else {
// operators for other mode.
}
1 |
if(mode==){ // operators for mode 0 }elseif(mode==1){ // operators for mode 1 }elseif(mode==2){ // operators for mode 2 }else{ // operators for other mode. } |
В куске кода, приведённом выше, проверяется значение переменной
mode. Для значений 0, 1 и 2 предусмотрены отдельные блоки кода, и ещё один блок кода предусмотрен для всех остальных значений. Оператор
switch делает то же самое, но делает код более наглядным:
Java
switch (mode) {
case 0:
// operators for mode 0
break;
case 1:
// operators for mode 1
break;
case 2:
// operators for mode 2
break;
default:
// operators for other mode
break;
}
1 |
switch(mode){ case // operators for mode 0 break; case1 // operators for mode 1 break; case2 // operators for mode 2 break; default // operators for other mode break; } |
Этот кусок кода с оператором
switch делает абсолютно то же самое, что и кусок кода с
if, рассмотренный до этого, но рекомендуется использовать вариант со
switch, так как он более нагляден.
Оператор
switch работает в следующем порядке:
- Вычисляется выражение в скобках (в данном примере оно состоит просто из переменной
mode ) - Полученное значение проверяется подряд со значениями в
case , и выполняется тот блок операторов, который относится к
case со значением, совпадающим со значением выражения. - Если ни одно из значений не совпало, то выполняется блок
default. - По ключевому слову
break выполнение блока внутри
case или
default завершается и управление передаётся на следующую инструкцию за блоком
switch.
С помощью
if-then и
if-then-else можно проверять любые условия, но с помощью
switch можно проверять только значения выражений типа
byte ,
short ,
char ,
int , перечисления (будет описано позднее),
String (начиная с Java SE 7), а также классы
java.lang.Byte ,
java.lang.Short ,
java.langCharacter ,
java.lang.Integer. Проверяемые значения в
case обязательно должны быть константными литералами. Если значение выражения в
switch равно
null, то возникает
java.lang.NullPointerException. Нагляднее всего
switch выглядит именно с перечислениями.
Ключевое слово
break не обязательно. В случае его отсутствия по завершении выполнения блока операторов внутри одного
case выполняются операторы следующего за ним
case. Это позволяет использовать один блок операторов для нескольких значений
case:
Java
switch (mode) {
case -1:
System.out.println(«mode -1»);
break;
case 0:
System.out.println(«mode 0»);
case 1:
case 2:
System.out.println(«mode 0 or 1 or 2»);
break;
case 3:
System.out.println(«mode 2»);
break;
default:
System.out.println(«mode default»);
break;
}
1 |
switch(mode){ case-1 System.out.println(«mode -1»); break; case System.out.println(«mode 0»); case1 case2 System.out.println(«mode 0 or 1 or 2»); break; case3 System.out.println(«mode 2»); break; default System.out.println(«mode default»); break; } |
Если
mode равно 0, то код выше выведет в консоль:
mode 0
mode 0 or 1 or 2
1 |
mode 0 mode 0 or 1 or 2 |
Если
mode равно 1, то код выше выведет в консоль:
mode 0 or 1 or 2
1 | mode 0 or 1 or 2 |
Если
mode равно 2, то код выше выведет в консоль:
mode 0 or 1 or 2
1 | mode 0 or 1 or 2 |
Блок
default не обязательно указывать в конце блока
switch. Он может стоять и в начале, и в середине (но рекомендуется всегда писать его последним, так получается гораздо нагляднее, потому что он выполняется в том случае, если ни один из
case -ов не подошёл):
Java
switch (mode) {
case 0:
System.out.println(«mode 0»);
break;
default:
System.out.println(«mode default»);
break;
case 1:
System.out.println(«mode 1»);
break;
case 2:
System.out.println(«mode 2»);
break;
}
1 |
switch(mode){ case System.out.println(«mode 0»); break; default System.out.println(«mode default»); break; case1 System.out.println(«mode 1»); break; case2 System.out.println(«mode 2»); break; } |
Можно даже вообще не указывать блок
default:
Java
switch (mode) {
case 0:
System.out.println(«mode 0»);
break;
case 1:
System.out.println(«mode 1»);
break;
case 2:
System.out.println(«mode 2»);
break;
}
1 |
switch(mode){ case System.out.println(«mode 0»); break; case1 System.out.println(«mode 1»); break; case2 System.out.println(«mode 2»); break; } |