Урок 6N: Массивы и Циклы

MainActivity

public class MainActivity extends AppCompatActivity {
private int[] numbers = {23,32,6,78,9};
private String[] texts = {"Привет","Как дела"};
private int[] numbers2 = new int[10];
private boolean is_start = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
numbers2[6] = 5;
numbers2[6] = 9;
is_start = false;
for(int i = 0; i < 10; i++)
{
Log.d("MyLog","Данные из i : " + i);
}
Log.d("MyLog","Данные из массива : " + numbers2[6]);
while(is_start)
{

}

do{

}while (is_start);




}

@Override
protected void onDestroy() {
super.onDestroy();

}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Цикл "for"

Конструкция for управляет циклами. Команда выполняется до тех пор, пока управляющее логическое выражение не станет ложным.

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


for(инициализация; логическое выражение (условие); шаг (итерация))
    команда

Любое из трёх выражений цикла (инициализация, логическое выражение или шаг) можно пропустить. Перед выполнением каждого шага цикла проверяется условие цикла. Если условие окажется ложным, то выполнение продолжится с инструкции, следующей за конструкцией for.

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

Как правило, цикл for используют для перебора. В качестве имени первой переменной часто используют i (сокр. от init), но вы можете использовать любое имя.

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

Третье выражение в цикле – шаг, то есть, на какое значение нужно изменить переменную. Строго говоря, в таком виде (x = x + 1) современные программисты не пишут, так как есть укороченная форма записи (x++). Предыдущий пример можно переписать по другому:


for (int x = 0; x < 9; x++)

Эта запись является классической и правильной, если нам нужно посчитать от 0 до 8. Может возникнуть соблазн написать, например, так:


for (int x = 0; x <= 8; x++)

Результат будет таким же, но такой код нежелателен. Старайтесь писать традиционно. Особенно это проявляется при работе с массивами.

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

С обычными числами обычно не работают в цикле for. Гораздо чаще цикл используют при работе с массивами.

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

int[] count = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = 0; i < count.length; i++)
    Log.d("MyLog","Счет : " + count[i]);

Мы создали массив из чисел от 0 до 9. Затем проходим в цикле, но на этот раз во втором операторе не используем число 9, а вычисляем длину массива. Такой гибкий подход позволят проделывать с массивами разные трюки – упорядочивать, сортировать, переворачивать и т.д.

Например, если мы хотим вывести числа в обратном порядке, меняем логику следующим образом. Теперь нам нужно начинать вывод не с 0, а с 9, т.е. int i = 9 или int i = count.length – 1 (для универсальности). Шаг будет не увеличиваться, а уменьшаться, значит – i–. А условием станет достижение 0, т.е. i >= 0. Проверяем.


int[] count = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = count.length - 1; i >= 0; i--) {
    Log.d("MyLog","Счет : " + count[i]);
}

С обычными числами обычно не работают в цикле for. Гораздо чаще цикл используют при работе с массивами.

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


int[] mice = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = 0; i < mice.length; i++)
    mInfoTextView.append(" " + mice[i]);

Мы создали массив из чисел от 0 до 9. Затем проходим в цикле, но на этот раз во втором операторе не используем число 9, а вычисляем длину массива. Такой гибкий подход позволят проделывать с массивами разные трюки – упорядочивать, сортировать, переворачивать и т.д.

Например, если мы хотим вывести числа в обратном порядке, меняем логику следующим образом. Теперь нам нужно начинать вывод не с 0, а с 9, т.е. int i = 9 или int i = mice.length – 1 (для универсальности). Шаг будет не увеличиваться, а уменьшаться, значит – i–. А условием станет достижение 0, т.е. i >= 0. Проверяем.


int[] mice = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = mice.length - 1; i >= 0; i--) {
    mInfoTextView.append(" " + mice[i]);
}

Аналог foreach

Во многих языках существует более компактная форма for для перебора элементов массивов – foreach. Конструкция foreach не требует ручного изменения переменной-шага для перебора – цикл автоматически выполняет эту работу.

В Java решили не добавлять новое ключевое слово, а просто сделали усовершенствованный вид цикла for, который имеет вид:

for(тип итер_пер : коллекция) блок_операторов

Для сравнения напишем цикл для вычисления суммы значений элементов массива традиционным способом:


int[] nums = { 1, 2, 3, 4, 5 };
int sum = 0;

for(int i = 0; i < 5; i++) sum += nums[i];

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


int[] nums = { 1, 2, 3, 4, 5 };
int sum = 0;

for(int i : nums) sum += i;

При прохождении цикла переменной i автоматически присваивается значение, равное значению следующего элемента массива nums. Таким образом, при первом прохождении переменная i содержит значение 1, при втором – 2 и т.д. Кроме того при таком способе исключается возможность ошибок выхода за пределы массива.

Для этого способа можно использовать массив или любой класс с интерфейсом Iterable.

Можно прервать выполнение цикла с помощью оператора break:


int[] nums = { 1, 2, 3, 4, 5 };
int sum = 0;

for(int i : nums) {
    sum += i;
	if(i == 3) break; // останавливаем цикл, если значение равно 3
}

Учтите, что в цикле в стиле foreach итерационная переменная доступна только для чтения, так как она связана только с исходным массивом. Даже если вы измените её значение, то это не повлияет на работу с массивом.

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

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


int[] nums = { 3, 1, 6, 4, 9, 5, 8, 2 };

int val = 5;
boolean found = false;

// ищем значение 5 в массиве
for (int x : nums) {
	if (x == val) {
		found = true;
		break;
	}
}

if (found) {
	Log.d("MyLog","Значение найдено");
}

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

Вложенные циклы

Также допустимо использование вложенных циклов, когда один цикл выполняется внутри другого:


int i, j;

for (i = 0; i < 10; i++) {
	for (j = i; j < 10; j++) {
		mInfoTextView.append("*");
	}
	mInfoTextView.append("\n");
}

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

**********
*********
********
*******
******
*****
****
***
**
*

При вложенных циклах количество повторений перемножается. В предыдущем примере было 100 повторений. Например, можно написать таблицу умножения.


int i, j, a = 0;

for (i = 1; i < 10; i++) {
	for (j = 1; j < 10; j++) {
		a = i * j;
		System.out.print(a + " | ");
	}
	System.out.println();
}

Результат смотрите в вкладке LogCat.

Цикл for является более удобным вариантом цикла while.


for(int i = 10; i > 0; i--){
    System.out.println("Отсчёт пошёл... " + i);
}

Этот же вариант с while:


int i = 10;
while(i > 0){
    System.out.println("Отсчёт пошёл... " + i);
    i--;
}

С помощью цикла можно рисовать красивые узоры, меняя координаты одной фигуры.

Цикл while

Бесконечный цикл

Оператор цикла while есть практически во всех языках программирования. Он повторяет оператор или блок операторов до тех пор, пока значение его управляющего выражения истинно.

Форма цикла while следующая:


while(условие) {
    // тело цикла
}

Здесь условие должно быть любым булевым выражением. Тело цикла будет выполняться до тех пор, пока условное выражение истинно. Когда условие становится ложным, управление передаётся строке кода, которая идёт после цикла. Если в цикле используется только один оператор, то фигурные скобки можно опустить (но лучше так не делать).

Логическое выражение вычисляется перед началом цикла, а затем каждый раз перед выполнением очередного повторения оператора.

Напишем пример с использованием цикла while, который выполняет обратный отсчёт от 10 до 0:


int counter = 10;
while (counter > 0) {
    mInfoTextView.append("Осталось " + counter + " сек.\n");
	counter--;
}

Программа выведет десять строк:


Осталось 10 сек.
Осталось 9 сек.
Осталось 8 сек.
Осталось 7 сек.
Осталось 6 сек.
Осталось 5 сек.
Осталось 4 сек.
Осталось 3 сек.
Осталось 2 сек.
Осталось 1 сек.

Если нужно увеличивать от единицы до 10, то код будет следующим.


int counter = 1;
while(counter < 11){
    System.out.println(counter);
    counter++;
}

Поскольку цикл while вычисляет своё условное выражение в начале цикла, то тело цикла не будет выполняться, если условие с самого начала было ложным.


boolean isHungry; // голоден ли кот
isHungry = true; // где вы видали сытого кота?
while(!isHungry) {
    mInfoTextView.setText("Случилось чудо - кот не голоден");
}

Вы никогда не увидите сообщение, так как сытый кот – это из области фантастики.

Обратный пример – бесконечный цикл. Создадим условие, которое всегда имеет значение true.


boolean isHungry; // голоден ли кот
isHungry = true;
while(isHungry) {
    System.out.println("Кот голодный...");
}

В логах будет постоянно выводиться надпись “Кот голодный…”.

Тело цикла while может быть пустым. Например:


int i, j;
i = 10;
j = 30;
// вычисляем среднее значение двух переменных
while (++i < --j)
	; // у цикла нет тела
mInfoTextView.setText("Среднее значение равно " + i);

Пример работает следующим образом. Значение переменной i увеличивается, а значение переменной j уменьшается на единицу. Затем программа сравнивает два новых значения переменных. Если новое значение переменной i меньше нового значения переменной j, то цикл повторяется. На каком-то этапе значения обоих переменных сравняются и цикл прекратит свою работу. При этом переменная i будет содержать среднее значение исходных значений двух переменных. Достаточно изуверский способ вычисления среднего значения, но здесь главное увидеть пример цикла без тела. Все действия выполняются внутри самого условного выражения. Учтите, если значение первой переменной с самого начала будет больше второй переменной, то код пойдёт коту под хвост.

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

Числа Фибоначчи

О числах Фибоначчи почитайте в Википедии. А мы напишем пример, выводящий все числа до 150 при помощи цикла while:


private void showFibonacci() {
	int num1 = 0;
	int num2 = 1;
	int result = num1 + num2;
	
	Log.d("MyLog",""num1 + " " + num2);
	while (result < 150) {
		Log.d("MyLog","Результат" + result);
		num1 = num2;
		num2 = result;
		result = num1 + num2;
	}
}

Циклы for и while взаимозаменяемы. Любой из них можно переписать в другой.

Массив

В любом языке программирования используются массивы, удобные для работы с большим количеством однотипных данных. Если вам нужно обработать сотни переменных, то вызывать каждую по отдельности становится муторным занятием. В таких случаях проще применить массив. Для наглядности представьте себе собранные в один ряд пустые коробки. В каждую коробочку можно положить что-то одного типа, например, котов. Теперь, даже не зная их по именам, вы можете выполнить команду Накормить кота из 3 коробки. Сравните с командой Накормить Рыжика. Чувствуете разницу? Вам не обязательно знать котов по именам, но вы всё равно сможете справиться с заданием. Завтра в этих коробках могут оказаться другие коты, но это не составит для вас проблемы, главное знать номер коробки, который называется индексом.

Массив

Еще раз повторим теорию. Массивом называется именованное множество переменных одного типа. Каждая переменная в данном массиве называется элементом массива. Чтобы сослаться на определённый элемент в массиве нужно знать имя массива в соединении с целым значением, называемым индексом. Индекс указывает на позицию конкретного элемента относительно начала массива. Обратите внимание, что первый элемент будет иметь индекс 0, второй имеет индекс 1, третий – индекс 2 и так далее. Данное решение было навязано математиками, которым было удобно начинать отсчёт массивов с нуля.

Объявление массива

Переменную массива можно объявить с помощью квадратных скобок:


int[] cats;  // мы объявили переменную массива

Возможна и альтернативная запись:


int cats[]; // другой вариант

Здесь квадратные скобки появляются после имени переменной. В разных языках программирования используются разные способы, и Java позволяет вам использовать тот вариант, к которому вы привыкли. Но большинство предпочитает первый вариант. Сами квадратные скобки своим видом напоминают коробки, поэтому вам будет просто запомнить.

Мы пока только объявили массив, но на самом деле его ещё не существует, так как не заполнен данными. Фактически значение массива равно null.

Определение массива

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


cats = new int[10];

Можно одновременно объявить переменную и определить массив (в основном так и делают):


int[] cats = new int[10];

Если массив создаётся таким образом, то всем элементам массива автоматически присваиваются значения по умолчанию. Например, для числовых значений начальное значение будет 0. Для массива типа boolean начальное значение будет равно false, для массива типа char – ‘\u0000’, для массива типа класса (объекты) – null.

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


String[] catNames = new String[10];

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


for (int i = 0; i < 10; i++)
        catNames[i] = "";

Доступ к элементам массива

Обращение к элементу массива происходит по имени массива, за которым следует значение индекса элемента, заключённого в квадратные скобки. Например, на первый элемент нашего массива cats можно ссылаться как на cats[0], на пятый элемент как cats[4].

В качестве индекса можно использовать числа или выражения, которые создают положительное значение типа int. Поэтому при вычислении выражения с типом long, следует преобразовать результат в int, иначе получите ошибку. С типами short и byte проблем не будет, так как они полностью укладываются в диапазон int.

Инициализация массива

Не всегда нужно иметь значения по умолчанию. вы можете инициализировать массив собственными значениями, когда он объявляется, и определить количество элементов. Вслед за объявлением переменной массива добавьте знак равенства, за которым следует список значений элементов, помещенный в фигурные скобки. В этом случае ключевое слово new не используется:


int[] cats = {2, 5, 7, 8, 3, 0};  // массив из 6 элементов

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


int[] cats = new int[6]; // массив из шести элементов с начальным значением 0 для каждого элемента
cats[3] = 5; // четвертому элементу присвоено значение 5
cats[5] = 7; // шестому элементу присвоено значение 7

Массивы часто используют в циклах. Допустим, 5 котов отчитались перед вами о количестве пойманных мышек. Как узнать среднее арифметическое значение:


int[] mice = {4, 8, 10, 12, 16};
int result = 0;

for(int i = 0; i < 5; i++){
	result = result + mice[i];
}
result = result / 5;
Log.d("MyLog","Среднее арифметическое: " + result);

Массив содержит специальное поле length, которое можно прочитать (но не изменить). Оно позволяет получить количество элементов в массиве. Данное свойство удобно тем, что вы не ошибётесь с размером массива. Последний элемент массива всегда mice[mice.length – 1]. Предыдущий пример можно переписать так:


int[] mice = { 4, 8, 10, 12, 16 };
int result = 0;

for (int i = 0; i < mice.length; i++) {
	result = result + mice[i];
}
result = result / mice.length; // общий результат делим на число элементов в массиве
Log.d("MyLog","Среднее арифметическое: " + result);

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

Если вам нужно изменять длину, то вместо массива следует использовать списочный массив ArrayList. Сами массивы неизменяемы.

Будьте осторожны с копированием массивов. Массив – это не числа, а специальный объект, который по особому хранится в памяти. Чтобы не загромождать вас умными словами, лучше покажу на примере.

Допустим, у нас есть одна переменная, затем мы создали вторую переменную и присвоили ей значение первой переменной. А затем проверим их.


int a = 5;
int b = a;
Log.d("MyLog","a = " + a + "\nb = " + b);

Получим ожидаемый результат.


a = 5
b = 5

Попробуем сделать подобное с массивом.


int[] anyNumbers = {2, 8, 11};
int[] luckyNumbers = anyNumbers;
luckyNumbers[2] = 25;
Log.d("MyLog","anyNumbers: " + Arrays.toString(anyNumbers)
        + "\nluckyNumbers: " + Arrays.toString(luckyNumbers));

Получим результат.


anyNumbers: [2, 8, 25];
luckyNumbers: [2, 8, 25];

Мы скопировали первый массив в другую переменную и в ней поменяли третий элемент. А когда стали проверять значения у обоих массивов, то оказалось, что у первого массива тоже поменялось значение. Но мы же его не трогали! Магия. На самом деле нет, просто массив остался прежним и вторая переменная обращается к нему же, а не создаёт вторую копию. Помните об этом.

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

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

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

Ваш адрес email не будет опубликован.