Usa sempre numeri interi, a meno che tu non abbia una buona ragione per fare altrimenti. Qui, in realtà abbiamo una buona ragione: i numeri di porta devono essere compresi nell'intervallo da 0 a 2 16 -1 (vale a dire in un numero a 16 bit senza segno).
Sfortunatamente, il short
di Java è un numero firmato a 16 bit, con l'intervallo -2 15 a 2 15 -1. Se utilizzi i corti nella tua API, la porta 65535 dovrebbe essere specificata come -1
. Questo potrebbe essere capito correttamente da una API C che getta il numero su un'interpretazione non firmata, ma all'interno di Java questo porterà a un sacco di dolore non necessario. In particolare, -1 != 65535
, e non puoi facilmente verificare se una determinata porta si trova all'interno di un intervallo di porte.
Se sei preoccupato della correttezza, allora prendi provvedimenti per assicurarti la correttezza. Possiamo modellare un concetto come un "numero di porta valido" come nuovo tipo:
class ValidPortNumber {
private static final MIN_PORT = 0;
private static final MAX_PORT = 65535;
private final int port;
public ValidPortNumber(int port) {
if (!(MIN_PORT <= port && port <= MAX_PORT))
throw ...;
this.port = port;
}
public int get() { return port; }
}
In alternativa, puoi eseguire questa convalida nella tua classe socket.
Perché non possiamo fare affidamento sull'intervallo di valori dei tipi primitivi invece di eseguire la convalida? Quando si mappano concetti (come numeri di porta) a un'implementazione (come i tipi numerici), ci può sempre essere una mancata corrispondenza:
-
alcune istanze del concetto non possono essere mappate all'implementazione, poiché l'implementazione è troppo limitata. Questo succede più o meno se tu avessi scelto short
, poiché new ServerSocket(65535)
non avrebbe funzionato! Per un'implementazione corretta, è necessario che non esiste alcuna corrispondenza errata.
-
l'implementazione può rappresentare valori che non sono istanze del concetto. Questo succederebbe se usassi int
s senza alcuna convalida, poiché new ServerSocket(65536)
sarebbe stato accettato. Eliminare questa discrepanza non è strettamente necessario per una corretta implementazione, ma è necessario rilevare l'input falso e rendere l'implementazione resiliente contro i bug di utilizzo.
Quindi ricorda: ogni numero di porta è un numero intero, ma non ogni numero intero è un numero di porta. Pertanto, dovrai scrivere il codice di convalida. Non è possibile utilizzare i cortocircuiti poiché non tutti i numeri di porta sono abbreviati e non tutti i cortometraggi firmati sono un numero di porta.
Esercizi
Le risposte vengono visualizzate al passaggio del mouse sopra la citazione.
-
posso rappresentare il concetto "Indirizzo" come il tipo "String"?
Yes, every address can be represented as a string. However, I should create a custom type with validation since some strings such as "92hhef92fdff#as"
aren't usable addresses.
-
posso rappresentare il concetto "Nome" come il tipo "String"?
Yes, every name can be written in a Unicode string. Since it is not possible to validate whether a name is “correct”, it is not useful to add a validation type. While some names cannot be expressed in script, this is outside of the scope of any reasonable model of names.
-
posso rappresentare il concetto "Numero telefonico" come il tipo "int"?
No, for a variety of reasons: leading zeroes might be significant (e.g. for international calls), or because digits might be grouped with spaces, parens, hyphens, … for better readability. Some numbers might use letters as mnemonics for numbers. However, every telephone number can be represented as a sequence of digits (plus perhaps the +
and #
chars?). We should therefore define a custom type to provide validation and a correct concept of equality, but we could use a string to store the digit sequence and possibly any user-supplied formatting.