Как сделать калькулятор на java
Зная некоторые основы компоновки и такие элементы как TextView, EditText и Button, уже можно составить более менее полноценное приложение. В данном случае мы сделаем простенький калькулятор.
Для этого создадим новый проект и определим в файле activity_main.xml следующий интерфейс:
В итоге весь интерфейс будет выглядеть следующим образом:
Корневой контейнер компоновки представляет элемент ConstraintLayout . Сверху в нем определены два текстовых поля TextView: одно для вывода результата вычислений и одно для вывода текущего знака операции.
Затем идет элемент EditText, предназначенный для ввода чисел.
И далее расположены четыре элемента LinearLayout с горизонтальными рядами кнопок. Чтобы все кнопки занимали равное пространство внутри контейнера, для них установлены атрибуты android:layout_weight=»1″ и android:layout_width=»0dp» .
Для каждой кнопки установлен идентификатор, чтобы в коде можно было прикрепить к ней определенный обработчик нажатия.
Теперь изменим класс MainActivity :
package com.metanit.calculator; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity < TextView resultField; // текстовое поле для вывода результата EditText numberField; // поле для ввода числа TextView operationField; // текстовое поле для вывода знака операции Double operand = null; // операнд операции String lastOperation = "="; // последняя операция @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // получаем все поля по id из activity_main.xml resultField = findViewById(R.id.resultField); numberField = findViewById(R.id.numberField); operationField = findViewById(R.id.operationField); findViewById(R.id.add).setOnClickListener((view)->onOperationClick("+")); findViewById(R.id.sub).setOnClickListener((view)->onOperationClick("-")); findViewById(R.id.mul).setOnClickListener((view)->onOperationClick("*")); findViewById(R.id.div).setOnClickListener((view)->onOperationClick("/")); findViewById(R.id.eq).setOnClickListener((view)->onOperationClick("=")); findViewById(R.id.n0).setOnClickListener((view)->onNumberClick("0")); findViewById(R.id.n1).setOnClickListener((view)->onNumberClick("1")); findViewById(R.id.n2).setOnClickListener((view)->onNumberClick("2")); findViewById(R.id.n3).setOnClickListener((view)->onNumberClick("3")); findViewById(R.id.n4).setOnClickListener((view)->onNumberClick("4")); findViewById(R.id.n5).setOnClickListener((view)->onNumberClick("5")); findViewById(R.id.n6).setOnClickListener((view)->onNumberClick("6")); findViewById(R.id.n7).setOnClickListener((view)->onNumberClick("7")); findViewById(R.id.n8).setOnClickListener((view)->onNumberClick("8")); findViewById(R.id.n9).setOnClickListener((view)->onNumberClick("9")); findViewById(R.id.comma).setOnClickListener((view)->onNumberClick(",")); > // сохранение состояния @Override protected void onSaveInstanceState(Bundle outState) < outState.putString("OPERATION", lastOperation); if(operand!=null) outState.putDouble("OPERAND", operand); super.onSaveInstanceState(outState); >// получение ранее сохраненного состояния @Override protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) < super.onRestoreInstanceState(savedInstanceState); lastOperation = savedInstanceState.getString("OPERATION"); operand= savedInstanceState.getDouble("OPERAND"); resultField.setText(operand.toString()); operationField.setText(lastOperation); >// обработка нажатия на числовую кнопку public void onNumberClick(String number) < numberField.append(number); if(lastOperation.equals("=") && operand!=null)< operand = null; >> // обработка нажатия на кнопку операции public void onOperationClick(String op)< String number = numberField.getText().toString(); // если введенно что-нибудь if(number.length()>0)< number = number.replace(',', '.'); try< performOperation(Double.valueOf(number), op); >catch (NumberFormatException ex) < numberField.setText(""); >> lastOperation = op; operationField.setText(lastOperation); > private void performOperation(Double number, String operation) < // если операнд ранее не был установлен (при вводе самой первой операции) if(operand ==null)< operand = number; >else < if(lastOperation.equals("="))< lastOperation = operation; >switch(lastOperation) < case "=": operand =number; break; case "/": if(number==0)< operand =0.0; >else < operand /=number; >break; case "*": operand *=number; break; case "+": operand +=number; break; case "-": operand -=number; break; > > resultField.setText(operand.toString().replace('.', ',')); numberField.setText(""); > >
Разберем этот код. Вначале в методе onCreate() получаем все поля из activity_main.xml, текст которых будет изменяться:
resultField = findViewById(R.id.resultField); numberField = findViewById(R.id.numberField); operationField = findViewById(R.id.operationField);
Далее для каждой кнопки назначаем определенный обработчик нажатия — в зависимости от типа кнопки это либо метод onNumberClick , в который передается нажатое число, либо onOperationClick , в который передается знак операции.
Результат операции будет попадать в переменную operand, которая представляет тип Double, а знак операции — в переменную lastOperation:
Double operand = null; String lastOperation = " brush:java;"> numberField.append(number); if(lastOperation.equals(" равно"), то мы сбрасываем переменную operand.В методе
onOperationClick
происходит обработка нажатия на кнопку со знаком операции:String number = numberField.getText().toString(); if(number.length()>0)< number = number.replace(',', '.'); try< performOperation(Double.valueOf(number), op); >catch (NumberFormatException ex) < numberField.setText(""); >> lastOperation = op; operationField.setText(lastOperation);Здесь получаем ранее введенное число и введенную операцию и передаем их в метод performOperation() . Так как в метод передается не просто строка, а число Double, то нам надо преобразовать строку в чсло. И поскольку теоретически могут быть введены нечисловые символы, то для отлова исключения, которое может возникнуть при преобразовании используется конструкция try. catch.
Кроме того, так как разделителем целой и дробной части в Double в java является точка, то нам надо заменить запятую на точку, так как предполагается, что мы используем в качестве разделителя запятую.
А методе performOperation() выполняем собственно операцию. При вводе первой операции, когда операнд еще не установлен, мы просто устанавливаем операнд:
if(operand ==null)
При вводе второй и последующих операций применяем предыдущую операцию, знак которой хранится в переменной lastOperation, к операнду operand и второму числу, которое было введено в числовое поле. Полученный результат операции сохраняем в переменной operand.
Как сделать однострочный калькулятор?
Забираешь строку целиком со сканера. Если примеры простые, то парсишь ее, чтоб понять какие числа и какая операция и считаешь. Если примеры сложные где надо учитывать порядок вычисления, то используй метод обратной польской записи, алгоритм можно посмотреть здесь http://www.interface.ru/home.asp?artid=1492
Максимально просто в лоб
public static void main(String[]args)< Scanner in = new Scanner( System.in); String str = in.next(); Double result = null; String[] numbers; if(str.indexOf( '+' )>0)< numbers = str.split( "[+]" ); result = Double.parseDouble( numbers[0] ) + Double.parseDouble( numbers[1] ); >else if(str.indexOf( '-' )>0)< numbers = str.split( "[-]" ); result = Double.parseDouble( numbers[0] ) - Double.parseDouble( numbers[1] ); >else if(str.indexOf( '/' )>0)< numbers = str.split( "[/]" ); result = Double.parseDouble( numbers[0] ) / Double.parseDouble( numbers[1] ); >else if(str.indexOf( '*' )>0)< numbers = str.split( "[*]" ); result = Double.parseDouble( numbers[0] ) * Double.parseDouble( numbers[1] ); >else < >System.out.println(result); >
здесь не учтены обработка ошибок ввода, обработка исключений и т.д. это вам надо доработать
Калькулятор на Java с базой лишь в 10 лвл JavaRush (3Kyu задача на CodeWars)
Очередная статья про мои приключения на CodeWars. На этот реализуем функционал элементарного калькулятора: Create a simple calculator that given a string of operators (), +, -, *, /. У меня за плечами лишь 10+ уровней JavaRush, поэтому код довольно громоздок, но функционирует отлично. Задача как вы могли заметить, с сайта CodeWars . Ее ранг — 3kyu . ссылку могу дать в личке. Вот частичный список методов и процессов, которые мне помогли:
- Рекурсия. Процесс, при котором метод вызывает сам себя (впервые его применил:)), в данном случае необходима, чтобы избавиться от скобок.
- Методы String 'a trim() , split() , substring() , replace() .
- Базовые методы коллекции List .
- А также преобразование типов Double в String и назад.
В принципе, этого хватает. Прежде чем перейти к самому коду, расскажу на какие подводные камни я наткнулся. В большинстве своем, это порядок выполнения вычислений, сначала я сделал стандартную схему * > / > + > - , однако понял, что например при вот таком варианте: 12/6 * 32/2 , программа сначала выполнит умножение ( 6*32 ) и все пойдет под откос, так что очередность стала такой: * > / > + > - . Еще через пару часов наткнулся на самый большой камушек — - . В разных позициях и при разных комбинациях он менял ВСЕ . (Тут конечно есть и моя вина, т.к., например: -34 , лежит у меня не в одной ячейке списка, а в двух: в одной, - в другой, 34 ). Из-за этого пришлось прописывать 2 дополнительные логики в вычисления с - , вообщем увидите это в коде. Извиняюсь за излишние комментарии в коде, я хотел максимально раскрыть ход своих мыслей и объяснить, что там вообще происходит.
import java.util.*; public class Calculator < public static void main(String[] args) < String num = "2 / ( ( 2 + 0 ) * 1 ) - 6"; System.out.println(evaluate(num)); >public static Double evaluate(String expression) < // Этап 1 // На данном этапе преобразуем нашу строку в список строк, через совмещение цикла for-each и метода split(), // также используем метод trim(), чтобы избавиться от пробелов по краям. // Обратите внимание, что каждым вторым элиментом я добавляю " ". Для того, чтобы потом мне было легче работать со строкой List
strList = new ArrayList<>(); for (String listElement : expression.trim().split(" ")) < strList.add(listElement); strList.add(" "); >strList.remove(strList.size() - 1); // for (String x : strList) System.out.print(x + ""); // System.out.println(); // После того, как дочитаете код до конца, расскоментируйте две верхние строчки // и посмотрите как работает рекрусия // Этап 2 // Производим поиск символа "(" в списке если находим, то преобразуем все символы от '(' до последнего ')' в строку. // Надо быть внимательными и проверить на случай двух контрукций: 1) (()) 2) ()(). // P.S. После получения строки мы используем РЕКУРСИЮ (метод вызывает сам себя). Таким образом будем находить произведение скобок. if (strList.indexOf("(") != -1) < // Если "(" обнаружен, ищем подходящую конструкцию используя цикл. for (int i = strList.indexOf("(") + 1; i < strList.size() - 1; i++) < // // Конструкция 1: первым элиментом, который мы отыскали были вторые "(" String recursion = ""; if (strList.get(i).equals("(")) < for (int j = i; j < strList.lastIndexOf(")"); j++) < recursion += strList.get(j); >// сверху считывали последовательность находящуюся в скобках (()) До lastIndex элемента String test = expression.substring(expression.indexOf("("), expression.lastIndexOf(")") + 1); // test - последовательность как и сверху, но с добавлением скобок по краям // т.к. наш метод evaluate() возвращает Double, мы должны преобразовать результат рекрусии в String; String testRecursion = String.valueOf(evaluate(recursion)); expression = expression.replace(test, testRecursion); // преобразовали нашу строку с использование рекруси. Избавились от первых скобок strList.removeAll(strList); for (String newElement : expression.trim().split(" ")) < strList.add(newElement); strList.add(" "); >// Тут очищаем наш список и сново его заполняем (но уже раскрыв первые скобки) > // Конструкция 2: первым элиментом, который мы отыскали был ")" String recursion2 = ""; if (strList.get(i).equals(")")) < for (int j = strList.indexOf("(") + 1; j < strList.indexOf(")"); j++) < recursion2 += strList.get(j); >String test2 = expression.substring(expression.indexOf("("), expression.lastIndexOf(")") + 1); String testRecursion2 = String.valueOf(evaluate(recursion2)); expression = expression.replace(test2, testRecursion2); for (String newElement : expression.trim().split(" ")) < strList.add(newElement); strList.add(" "); >// Тут повторили тот же алгоритм, что и в первой конструкции > > > // Этап 3 // Заключительный этап на котором мы будем реализовывать сами вычесления (*/-+) // Всю реализацию помещаем в цикл while ( который прекратиться, если все действия будут выполнены (соответственно в списке останется 1 элемент)). // Внимательно посмотрите на порядок операций: 1)/ 2)* 3)- 4)+ // System.out.println(expression + "-------expression-"); // System.out.println(); // создаем очередной список для реализации вычеслений, на этот раз без добавления " ". List stringList2 = new ArrayList<>(); for (String element : expression.trim().split(" ")) < stringList2.add(element); >while (stringList2.size() != 0) < // работаем со списком: глубоком этапе рекрусии обрабатываем: (2+0) // на среднем: 1 * 1 "или вот этой части уравнения "( ( 2 + 0 ) * 1 ) " // Посмтортите сами // for (String x : stringList2) System.out.print(x ); // System.out.println(); // наш Double :) Также стоит обратить внимание, что для получения класса обертки мы используем не // Double.parseDouble() а Double.valueOf() Double result = 0d; // Сами алгоритмы вычеслений, впринципе понятны, поэтому не буду их комментировать. // Однако обратите внимание на очередность, особенно при вычетании (там вместо 1 условия, 3) // Если что в комментариях под постом немного объясню, если кто-нибудь дочитает до сюда и у него будет желание) if (stringList2.indexOf("/") != -1) < int index = stringList2.indexOf("/"); result = Double.valueOf(stringList2.get(index - 1)) / Double.valueOf(stringList2.get(index + 1)); stringList2.add(index - 1, String.valueOf(result)); stringList2.remove(index + 2); stringList2.remove(index + 1); stringList2.remove(index); >else if (stringList2.indexOf("*") != -1) < int index = stringList2.indexOf("*"); result = Double.valueOf(stringList2.get(index - 1)) * Double.valueOf(stringList2.get(index + 1)); stringList2.add(index - 1, String.valueOf(result)); stringList2.remove(index + 2); stringList2.remove(index + 1); stringList2.remove(index); >else if (stringList2.indexOf("-") != -1) < int index = stringList2.indexOf("-"); int lastIndex = stringList2.lastIndexOf("-"); if (index == 0) < result = 0.0 - Double.valueOf(stringList2.get(index + 1)); stringList2.add(0, String.valueOf(result)); stringList2.remove(2); stringList2.remove(1); >else if ((lastIndex-2>0) && (stringList2.get(lastIndex-2).equals("-"))) < result = Double.valueOf(stringList2.get(lastIndex + 1)) + Double.valueOf(stringList2.get(lastIndex - 1)); stringList2.add(lastIndex - 1, String.valueOf(result)); stringList2.remove(lastIndex + 2); stringList2.remove(lastIndex + 1); stringList2.remove(lastIndex); >else < result = Double.valueOf(stringList2.get(index - 1)) - Double.valueOf(stringList2.get(index + 1)); stringList2.add(index - 1, String.valueOf(result)); stringList2.remove(index + 2); stringList2.remove(index + 1); stringList2.remove(index); >> else if (stringList2.indexOf("+") != -1) < int index = stringList2.indexOf("+"); result = Double.valueOf(stringList2.get(index - 1)) + Double.valueOf(stringList2.get(index + 1)); stringList2.add(index - 1, String.valueOf(result)); stringList2.remove(index + 2); stringList2.remove(index + 1); stringList2.remove(index); >// Вот тут все немного коряво. (На всякий случий проверял отсутствие (*/+-)) if ((stringList2.indexOf("*") == -1) && (stringList2.indexOf("/") == -1) && (stringList2.indexOf("+") == -1) && (stringList2.indexOf("-") == -1)) < return result; >> return Double.valueOf(stringList2.get(0)); > >
Спасибо всем кто прочитал и оставил комментарий) Если есть замечания, а скорее всего они есть, буду рад услышать их)
- Покорение CodeWars (Решаем задачу 4kyu)
- Создание "Магического квадрата" в Java
Консольный калькулятор Java
Необходимо написать простой консольный калькулятор на Java.
- Метод int getInt() - должен считывать с консоли целое число и возвращать его
- Метод char getOperation() - должен считывать с консоли какое-то значение и возвращать символ с операцией (+, -, * или /)
- Метод int calc(int num1, int num2, char operation) - должен выполнять над числами num1 и num2 арифметическую операцию, заданную operation.
- Метод main() - должен считывать 2 числа (с помощью getInt()), считать операцию (с помощью getOperation(), передать все методу calc() и вывести на экран результат.
Решение:
import java . util . Scanner ;
public class Calculator <
static Scanner scanner = new Scanner ( System . in ) ;
public static void main ( String [ ] args ) <
int num1 = getInt ( ) ;
int num2 = getInt ( ) ;
char operation = getOperation ( ) ;
int result = calc ( num1 , num2 , operation ) ;
System . out . println ( "Результат операции: " + result ) ;
public static int getInt ( ) <
System . out . println ( "Введите число:" ) ;
if ( scanner . hasNextInt ( ) ) <
num = scanner . nextInt ( ) ;
System . out . println ( "Вы допустили ошибку при вводе числа. Попробуйте еще раз." ) ;
scanner . next ( ) ; //рекурсия
num = getInt ( ) ;
return num ;
public static char getOperation ( ) <
System . out . println ( "Введите операцию:" ) ;
char operation ;
if ( scanner . hasNext ( ) ) <
operation = scanner . next ( ) . charAt ( 0 ) ;
System . out . println ( "Вы допустили ошибку при вводе операции. Попробуйте еще раз." ) ;
scanner . next ( ) ; //рекурсия
operation = getOperation ( ) ;
return operation ;
public static int calc ( int num1 , int num2 , char operation ) <
int result ;
switch ( operation ) <
result = num1 + num2 ;
result = num1 - num2 ;
result = num1* num2 ;
result = num1 / num2 ;
System . out . println ( "Операция не распознана. Повторите ввод." ) ;
result = calc ( num1 , num2 , getOperation ( ) ) ; //рекурсия
return result ;
Комментарии к задаче:
Прежде чем решать данную задачу, необходимо разбить задачу на подзадачи. Как видно из картинки ниже, всего есть 3 основных шага:
Поэтому в методе int getInt() мы прописали механику считывания числа с консоли и проверки целочисленное число введено или нет.
public static int getInt ( ) < System . out . println ( "Введите число:" ) ; if ( scanner . hasNextInt ( ) ) < num = scanner . nextInt ( ) ; System . out . println ( "Вы допустили ошибку при вводе числа. Попробуйте еще раз." ) ; scanner . next ( ) ; //рекурсия num = getInt ( ) ; return num ;
- И потом просто в методе main() вызовем 2 раза метод int getInt(), потому что пользователь будет вводить 2 числа.
- Обратите внимание, что с помощью конструкции if-else мы прописали, что если число целочисленное, тогда присвоить введенное пользователем значение в переменную num, если же не целочисленное, - вывести в консоль "Вы допустили ошибку при вводе числа. Попробуйте еще раз".
- Также обратите внимание, что мы использовали рекурсию в else:
System . out . println ( "Вы допустили ошибку при вводе числа. Попробуйте еще раз." ) ;
scanner . next ( ) ; //рекурсия
num = getInt ( ) ;
Выбор операции (+,-,*,/) мы осуществили с помощью метода char getOperation()
public static char getOperation ( ) < System . out . println ( "Введите операцию:" ) ; char operation ; if ( scanner . hasNext ( ) ) < operation = scanner . next ( ) . charAt ( 0 ) ; System . out . println ( "Вы допустили ошибку при вводе операции. Попробуйте еще раз." ) ; scanner . next ( ) ; //рекурсия operation = getOperation ( ) ; return operation ;
Как видите, пользователю предлагается ввести операцию. А далее программа должна распознать было ли введенное пользователем значение типа char или нет. Причем нас устроит только, если пользователь введет: +, - , * или /. Например, если пользователь введет число, нас не устроит. Верно? Поэтому мы применили небольшую "хитрость" вот в этих 2 строчках кода:
if ( scanner . hasNext ( ) ) < operation = scanner . next ( ) . charAt ( 0 ) ;
Мы с помощью метода сканера next() считали всю строчку. А далее, поскольку нам не нужна вся строка, а нужен только первый элемент строки, то есть нулевой элемент, поэтому мы вызвали еще и метод charAt(0). И таким образом мы получим только значение 0-го элемента, а не всей строки.
Если вдруг подзабыли как работают методы сканера, перечитайте еще раз вот эту статью - "Работа со сканером в Java". А также, если необходимо вспомнить как работает метод charAt(), перечитайте вот эту статью - "charAt() в Java"
И далее мы прописали сам метод int calc(int num1, int num2, int operation):
public static int calc ( int num1 , int num2 , char operation ) < int result ; switch ( operation ) < result = num1 + num2 ; result = num1 - num2 ; result = num1* num2 ; result = num1 / num2 ; System . out . println ( "Операция не распознана. Повторите ввод." ) ; result = calc ( num1 , num2 , getOperation ( ) ) ; //рекурсия return result ;
Как видите, мы использовали конструкцию switch-case. И прописали, что:
- если пользователь ввел +, тогда num1+num2, то есть суммируем 2 числа, введенных пользователем.
- если пользователь ввел -, тогда num1-num2, то есть из 1-го числа, введенного пользователем вычитаем 2-е число
- и т.д.
Если вдруг Вам необходимо вспомнить как работает конструкция switch-case, перечитайте вот эту статью - "Условный оператор if в Java. Оператор switch"
Также обратите внимание, что здесь мы тоже использовали рекурсию. Вот в этих строчках кода:
System . out . println ( "Операция не распознана. Повторите ввод." ) ;
result = calc ( num1 , num2 , getOperation ( ) ) ; //рекурсия
И после того как мы прописали все необходимы методы, мы в методе main() прописали следующее:
public static void main ( String [ ] args ) < int num1 = getInt ( ) ; int num2 = getInt ( ) ; char operation = getOperation ( ) ; int result = calc ( num1 , num2 , operation ) ; System . out . println ( "Результат операции: " + result ) ;
- То есть в переменные num1 и num2 будут присвоены, соответственно, 1-е и 2-е число, введенное пользователем.
- В переменную operation будет присвоена операция, которую ввел пользователь: +, - , * или /
- Далее в переменную result будет присвоен результат вычислений "нашего калькулятора"
- И после этого результат будет выведен в консоль
Надеемся - наша статья была Вам полезна. Есть возможность записаться на наши курсы по Java. Детальную информацию смотрите у нас на сайте.
- ← Вывод фигуры из звездочек
- Java 8 CompletableFuture. Часть 3 - Конец →