Арифметические и математические операторы java с примерами

Математика

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
2
3
4
5
6
7
8
9

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
2
3
4

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
2
3
4
5
6
7
8

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

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
2
3
4
5
6
7

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> подходит к тому примеру, с которого мы начинали. Это значит, что мы можем передать в него аргументом код, который:

  1. принимает на вход два параметра (T t, U u). T и U указывают на то, что аргументы могут быть разных типов. Например, Long и String. Для нас это даже избыточно, у нас они одного типа — int;
  2. возвращает значение типа 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, нужно:

  1. Перевести значения обоих операндов в двоичную систему счисления.
  2. Расположить результаты перевода друг под другом.
  3. Сравнять в них число разрядов (дополнить лидирующими нулями).
  4. Применить к битам из каждого столбца оператор (&, | или ^).
  5. Записать результат каждой операции ниже в том же столбце.
  6. Перевести итог в десятичную форму.

Потренируемся: вычислим сами 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
2
3
4

for(intn=;n<=10;n++){

if(n%2==)continue;

System.out.println(n);

}

Выведет в консоль:

1
3
5
7
9

1
2
3
4
5

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
2
3
4
5
6
7
8
9
10
11
12
13

// …

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
2
3
4
5
6
7

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
2
3
4
5
6
7
8
9

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
2
3
4
5
6
7
8
9
10
11
12
13
14

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  работает в следующем порядке:

  1. Вычисляется выражение в скобках (в данном примере оно состоит просто из переменной
    mode )
  2. Полученное значение проверяется подряд со значениями в
    case , и выполняется тот блок операторов, который относится к
    case  со значением, совпадающим со значением выражения.
  3. Если ни одно из значений не совпало, то выполняется блок
    default.
  4. По ключевому слову
    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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

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
2

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
2
3
4
5
6
7
8
9
10
11
12
13
14

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
2
3
4
5
6
7
8
9
10
11

switch(mode){

case

System.out.println(«mode 0»);

break;

case1

System.out.println(«mode 1»);

break;

case2

System.out.println(«mode 2»);

break;

}

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

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

Adblock
detector