Как сделать калькулятор на java
Перейти к содержимому

Как сделать калькулятор на java

  • автор:

Как сделать калькулятор на java

Зная некоторые основы компоновки и такие элементы как TextView, EditText и Button, уже можно составить более менее полноценное приложение. В данном случае мы сделаем простенький калькулятор.

Для этого создадим новый проект и определим в файле activity_main.xml следующий интерфейс:

В итоге весь интерфейс будет выглядеть следующим образом:

Калькулятор на Android и Java

Корневой контейнер компоновки представляет элемент 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)

Калькулятор на Java с базой лишь в 10 лвл JavaRush (3Kyu задача на CodeWars) - 1

Очередная статья про мои приключения на CodeWars. На этот реализуем функционал элементарного калькулятора: Create a simple calculator that given a string of operators (), +, -, *, /. У меня за плечами лишь 10+ уровней JavaRush, поэтому код довольно громоздок, но функционирует отлично. Задача как вы могли заметить, с сайта CodeWars . Ее ранг — 3kyu . ссылку могу дать в личке. Вот частичный список методов и процессов, которые мне помогли:

  1. Рекурсия. Процесс, при котором метод вызывает сам себя (впервые его применил:)), в данном случае необходима, чтобы избавиться от скобок.
  2. Методы String 'a trim() , split() , substring() , replace() .
  3. Базовые методы коллекции List .
  4. А также преобразование типов 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(), чтобы избавиться от пробелов по краям. // Обратите внимание, что каждым вторым элиментом я добавляю " ". Для того, чтобы потом мне было легче работать со строкой ListstrList = 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)); > > 

Java-университет

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

  • Покорение 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 - Конец →

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

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