Присоединяйтесь к JAVA FLAMES

Многим трудно понять разницу между семантическими ошибками и синтаксическими (синтаксическими) ошибками в коде Java, но они разные. Вы можете увидеть семантическую ошибку, когда синтаксис вашего кода правильный, но использование кода неправильное.

· Что такое семантическая ошибка?
· Как обнаруживаются семантические ошибки?
· Распространенные семантические ошибки

Что такое смысловая ошибка?

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

var a = 1 // No error
var b = 2 // No error
var c = 3 // No error
a + c = b

Семантическая ошибка — это ошибка на уровне языка в программе, обычно возникающая при попытке использовать идентификатор, который не был определен ранее.

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

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

Как обнаруживаются семантические ошибки?

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

На данный момент мы описали статические семантические ошибки. В каждом случае компилятор помечает статическую семантическую ошибку, когда требование языка программирования не выполняется (недопустимые типы).

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

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

Отладка не так проста с семантической ошибкой. Давайте посмотрим пример.

/**
 * This program prints the total benefit for the company
 * 
*/
public class TotalBenefit {
 public static void main(String[] args) {
  int branch1 = 250; 
        int branch2 = 500;
        System.out.println("The total benefit is  $" + (branch1 * branch2));
 }
}

Эта программа выведет Общая выгода $125000. Это неправильно; ожидаемый результат: 750 . Это происходит потому, что мы используем знак умножения ( * ) вместо знака сложения ( +).

Распространенные семантические ошибки

Ошибка несовместимых типов

Эта синтаксическая ошибка очень распространена среди начинающих. В скомпилированных языках программирования, таких как Java, вы можете присваивать значения только совместимым переменным.

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

В приведенном ниже примере вы можете видеть, что в Java вы не можете присвоить двойное значение целочисленной переменной. Некоторые языки программирования могут выполнять преобразование автоматически, но если вы видите приведенную ниже ошибку, исправить ее очень просто. Просто измените тип переменной «a» или присвойте целочисленное значение вместо двойного (5.5).

Этот тип семантической ошибки может быть сложным, потому что компилятор будет помечать одни ошибки, а другие нет. Например, если вы попытаетесь присвоить переменной типа int число с плавающей запятой, компилятор отобразит сообщение об ошибке.

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

«переменная ‹X› могла быть не инициализирована»

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

int x;
if (condition) {
  x = 5;
}
System.out.println(x); // x may not have been initialized

Выполнение невозможного броска

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

Ошибка «непреобразуемые типы» возникает, когда код Java пытается выполнить недопустимое преобразование.

TypeInvocationConversionTest.java:12: inconvertible types
found   : java.util.ArrayList<java.lang.Class<? extends TypeInvocationConversionTest.Interface1>>
required: java.util.ArrayList<java.lang.Class<?>>
lessRestrictiveClassList = (ArrayList<Class<?>>) classList;
                                                 ^

Например, логические значения нельзя преобразовать в целое число.

«нестатическая переменная . . . нельзя ссылаться из статического контекста»

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

public class StaticTest {
private int count=0;
   public static void main(String args[]) throws IOException {
       count++; //compiler error: non-static variable count cannot be referenced from a static context
   }
}

Чтобы исправить «нестатическую переменную . . . нельзя ссылаться из ошибки статического контекста», попробуйте следующие две вещи:

  • Объявите переменную статической в ​​подписи.
  • Проверьте код, так как он может создать экземпляр нестатического объекта в статическом методе.

«нестатический метод . . . нельзя ссылаться из статического контекста»

Эта проблема возникает, когда код Java пытается вызвать нестатический метод в нестатическом классе. Вот пример:

class Sample {
  private int age;
  public void setAge(int a) {
    age=a;
  }
  public int getAge() {
    return age;
  }
  public static void main(String args[]) {
    System.out.println(“Age is:”+ getAge());
   }
  }

Вернет эту ошибку:

Exception in thread “main” java.lang.Error: Unresolved compilation problem:
Cannot make a static reference to the non–static method getAge() from the type Sample

Вызов нестатического метода из статического метода означает объявление экземпляра класса, вызывающего нестатический метод.

Вы получите сообщение (массив) ‹X› не инициализирован, когда массив был объявлен, но не инициализирован. Массивы имеют фиксированную длину, поэтому каждый массив нужно инициализировать до нужной длины.

Допустим следующий код:

AClass[] array = {object1, object2}
  As is:
       AClass[] array = new AClass[2];
       …
       array[0] = object1;
       array[1] = object2;
  But not:
       AClass[] array;
       …
       array = {object1, object2};

«Оператор .. не может быть применен к ‹X›»

Эта проблема возникает, когда операторы используются для типов, а не в их определении.

Операторы определены только для определенных типов, хотя допускается неявное преобразование типов между определенными числовыми типами:

int a = 5; 
boolean b = true;
int c = a + b; // Error, can't add a boolean value double 
d = a + 1.4;  // OK, int is implicitly converted to double

Операция + не определена для типов аргументов int, boolean

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

Возможная потеря точности

Иногда вы можете применить кастинг неправильно. Например, приведение float к int работает нормально, но с потерей десятичной части числа.

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

Эта ошибка возникает при попытке присвоить значение более высокой точности переменной более низкой точности без явного приведения типа. Удивительно, но литералы с плавающей запятой имеют тип double, и вы получите это сообщение, если попытаетесь присвоить его переменной типа float:

float sum = 0.0;  // Error, literal is not of type float

Правильный способ сделать это — использовать литерал типа float или явное приведение типа:

float sum = 0.0f;   // OK float sum = (float) 0.0;  // OK

Несоответствие типов: невозможно преобразовать double в float

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

Неправильное применение области видимости

Любая переменная, которую вы объявляете внутри метода, имеет ту же область действия — другими словами, видимость для других частей приложения — что и метод. Следовательно, вы не можете объявить частную статическую переменную типа int внутри метода. Вместо этого вы должны определить переменную глобально следующим образом:

public class PrivateVar
{
   // This declaration works.
   private static int PrivateInt = 3;
   public static void main(String[] args)
   {
      // This declaration doesn’t work.
      private static int PrivateInt = 3;
   }
}

Другие распространенные семантические ошибки

Вот некоторые другие общие случаи семантических ошибок в Java.

Несоответствие типов. В C# существует множество способов использовать неправильный тип. Приведенный выше пример является одним из способов. Вот еще несколько возможных способов:

  • Передача неверного типа значения методу.
  • Возврат неправильного типа значения из метода.
  • Установка неправильного типа значения свойства.
  • Установка неправильного типа значения в поле.
  • Установка неправильного типа значения для локальной переменной.
  • Использование типа в общем списке аргументов, который не соответствует ограничениям универсального типа.

Несоответствие Arity. Это означает использование неправильного количества аргументов для чего-либо, и есть много способов сделать это:

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

Конфликты имен. Вот несколько способов, которыми могут конфликтовать имена:

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

Спасибо за чтение. Приятного обучения 😄

Поддержите нашу публикацию, подписавшись на нее